Django 无向唯一组合
Django undirected unique-together
我想对集合中所有成员之间的成对关系建模。
class Match(models.Model):
foo_a = models.ForeignKey(Foo, related_name='foo_a')
foo_b = models.ForeignKey(Foo, related_name='foo_b')
relation_value = models.IntegerField(default=0)
class Meta:
unique_together = ('ingredient_a', 'ingredient_b')
当我添加一对A-B时,它成功地阻止了我再次添加A-B,但没有阻止我添加B-A。
我试过跟随,但无济于事。
unique_together = (('ingredient_a', 'ingredient_b'), ('ingredient_b', 'ingredient_a'))
编辑:
我需要 relationship_value 对于每一对项目都是唯一的
如果你像你定义的那样定义一个模型,它不仅仅是一个外键,它被称为多对多关系。
在 django 文档中,明确定义了 ManyToMany 关系不能包含唯一在一起约束。
来自文档,
A ManyToManyField cannot be included in unique_together. (It’s not clear what that would even mean!) If you need to validate uniqueness related to a ManyToManyField, try using a signal or an explicit through model.
编辑
经过大量搜索和反复试验,我认为我终于找到了适合您的情况的解决方案。是的,正如您所说,目前的架构并不像我们所有人想象的那么微不足道。在这种情况下,Many to many relation 不是我们需要转发的讨论。解决方案是,(或者我认为的解决方案是)model clean method:
class Match(models.Model):
foo_a = models.ForeignKey(Foo, related_name='foo_a')
foo_b = models.ForeignKey(Foo, related_name='foo_b')
def clean(self):
a_to_b = Foo.objects.filter(foo_a = self.foo_a, foo_b = self.foo_b)
b_to_a = Foo.objects.filter(foo_a = self.foo_b, foo_b = self.foo_a)
if a_to_b.exists() or b_to_a.exists():
raise ValidationError({'Exception':'Error_Message')})
有关模型清理方法的更多详细信息,请参阅 docs here...
我重写了对象的保存方法,每次保存2对。如果用户要添加一对A-B,则自动添加一条参数相同的记录B-A。
注意:该方案影响查询速度。对于我的项目来说,这不是问题,但需要考虑。
def save(self, *args, **kwargs):
if not Match.objects.filter(foo_a=self.foo_a, foo_b=self.foo_b).exists():
super(Match, self).save(*args, **kwargs)
if not Match.objects.filter(foo_a=self.foo_b, foo_b=self.foo_a).exists():
Match.objects.create(foo_a=self.foo_b, foo_b=self.foo_a, bar=self.bar)
编辑:当然也需要重写更新和删除方法。
我想对集合中所有成员之间的成对关系建模。
class Match(models.Model):
foo_a = models.ForeignKey(Foo, related_name='foo_a')
foo_b = models.ForeignKey(Foo, related_name='foo_b')
relation_value = models.IntegerField(default=0)
class Meta:
unique_together = ('ingredient_a', 'ingredient_b')
当我添加一对A-B时,它成功地阻止了我再次添加A-B,但没有阻止我添加B-A。
我试过跟随,但无济于事。
unique_together = (('ingredient_a', 'ingredient_b'), ('ingredient_b', 'ingredient_a'))
编辑: 我需要 relationship_value 对于每一对项目都是唯一的
如果你像你定义的那样定义一个模型,它不仅仅是一个外键,它被称为多对多关系。
在 django 文档中,明确定义了 ManyToMany 关系不能包含唯一在一起约束。
来自文档,
A ManyToManyField cannot be included in unique_together. (It’s not clear what that would even mean!) If you need to validate uniqueness related to a ManyToManyField, try using a signal or an explicit through model.
编辑
经过大量搜索和反复试验,我认为我终于找到了适合您的情况的解决方案。是的,正如您所说,目前的架构并不像我们所有人想象的那么微不足道。在这种情况下,Many to many relation 不是我们需要转发的讨论。解决方案是,(或者我认为的解决方案是)model clean method:
class Match(models.Model):
foo_a = models.ForeignKey(Foo, related_name='foo_a')
foo_b = models.ForeignKey(Foo, related_name='foo_b')
def clean(self):
a_to_b = Foo.objects.filter(foo_a = self.foo_a, foo_b = self.foo_b)
b_to_a = Foo.objects.filter(foo_a = self.foo_b, foo_b = self.foo_a)
if a_to_b.exists() or b_to_a.exists():
raise ValidationError({'Exception':'Error_Message')})
有关模型清理方法的更多详细信息,请参阅 docs here...
我重写了对象的保存方法,每次保存2对。如果用户要添加一对A-B,则自动添加一条参数相同的记录B-A。
注意:该方案影响查询速度。对于我的项目来说,这不是问题,但需要考虑。
def save(self, *args, **kwargs): if not Match.objects.filter(foo_a=self.foo_a, foo_b=self.foo_b).exists(): super(Match, self).save(*args, **kwargs) if not Match.objects.filter(foo_a=self.foo_b, foo_b=self.foo_a).exists(): Match.objects.create(foo_a=self.foo_b, foo_b=self.foo_a, bar=self.bar)
编辑:当然也需要重写更新和删除方法。