使用以下代码:
class Organization(models.Model):
name = models.CharField(max_length="100",)
alias = models.SlugField()
...
class Division(Organization):
parent_org = models.ForeignKey(Organization)
class Meta:
unique_together=['parent_org', 'alias']
...
尝试syncdb给我这个错误:
Error: One or more models did not validate:
organizations.division: "unique_together" refers to alias. This is not in the
same model as the unique_together statement.
感谢任何帮助,
谢谢,
埃里克
答案 0 :(得分:14)
这是设计的。阅读unique_together选项的文档,它指出:
它在Django管理员中使用,在数据库级别强制执行。
如果查看子类创建的表,您将看到实际不具有其父级所具有的字段。相反,它使用名为[field]_ptr_id
的字段名称获取父表的软外键,其中[field]
是您从排除应用名称继承的表的名称。因此,您的分区表有一个名为organization_ptr_id
的主外键。
现在因为unique_together
使用UNIQUE
约束在数据库级别强制执行,所以我不知道数据库是否实际将其应用于不在表中的字段。
您最好的选择可能是在业务逻辑层使用Validators,或重新考虑数据库架构以支持约束。
编辑:正如Manoj指出的那样,您也可以尝试使用validate_unique
等Model Validators。
答案 1 :(得分:3)
[型号]验证器适合您。但也许最简单的方法是使用:
class BaseOrganization(models.Model):
name = models.CharField(max_length="100",)
alias = models.SlugField()
class Meta:
abstract = True
class Organization(BaseOrganization):
pass
class Division(BaseOrganization):
parent_org = models.ForeignKey(Organization)
class Meta:
unique_together=['parent_org', 'alias']
注意:与您当前的代码一样,您无法进行细分。
答案 2 :(得分:2)
这是我最近在Django 1.6中使用的解决方案(感谢Manoj Govindan的想法):
class Organization(models.Model):
name = models.CharField(max_length="100",)
alias = models.SlugField()
...
class Division(Organization):
parent_org = models.ForeignKey(Organization)
# override Model.validate_unique
def validate_unique(self, exclude=None):
# these next 5 lines are directly from the Model.validate_unique source code
unique_checks, date_checks = self._get_unique_checks(exclude=exclude)
errors = self._perform_unique_checks(unique_checks)
date_errors = self._perform_date_checks(date_checks)
for k, v in date_errors.items():
errors.setdefault(k, []).extend(v)
# here I get a list of all pairs of parent_org, alias from the database (returned
# as a list of tuples) & check for a match, in which case you add a non-field
# error to the error list
pairs = Division.objects.exclude(pk=self.pk).values_list('parent_org', 'alias')
if (self.parent_org, self.alias) in pairs:
errors.setdefault(NON_FIELD_ERRORS, []).append('parent_org and alias must be unique')
# finally you raise the ValidationError that includes all validation errors,
# including your new unique constraint
if errors:
raise ValidationError(errors)
答案 3 :(得分:2)
这并不是严格适用于这个问题,而是非常密切相关的;如果基类是抽象的,unique_together
将起作用。您可以使用以下方式标记抽象模型类:
class Meta():
abstract = True
这将阻止django为类创建表,并且其字段将直接包含在任何子类中。在这种情况下,unique_together
是可能的,因为所有字段都在同一个表中。
https://docs.djangoproject.com/en/1.5/topics/db/models/#abstract-base-classes
答案 4 :(得分:0)
当尝试将unique_together应用于给定客户端创建的权限组时,我遇到了类似的挑战。
class ClientGroup(Group):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
is_active = models.BooleanField()
class Meta():
# looking at the db i found a field called group_ptr_id.
# adding group_ptr did solve the problem.
unique_together = ('group_ptr', 'client', 'is_active')