2017-04-19 81 views
0

我试图验证一个模型,指定父母模型的ManyToManyField在祖父母模型中是唯一的。如果不同的祖父母有同名的孙辈,但祖父母可能没有两个同名的孙辈,这很好。使用ManyToManyField验证祖父母内的唯一性

This question讨论一个解决方案,如果关系是ForignKey s,但在这里不起作用。在我可以参考父母进行测试以确定其是否在GrandParent内是唯一的之前,GrandChild必须得到保存。

由于父母在GrandChild存在之前不能附属,所以GrandChild的独特性如何与GrandParent进行验证?

class GrandParent(models.Model): 
    name = models.CharField(max_length=255) 

class Parent(models.Model): 
    name = models.CharField(max_length=255) 
    grandparent = models.ForeignKey(GrandParent) 

    class Meta: 
     unique_together('name', 'GrandParent')  

class GrandChild(models.Model): 
    name = models.CharField(max_length=255) 
    parents = models.ManyToManyField(Parent) 

    def validate_unique(self, exclude=None): 
     # validate that GrandChild is unique within a given GrandParent 

我尝试添加了save()方法给孙子方法

def save(self, *args, **kwargs): 
    grand_parent = self.parents.all()[0].grandparent 
    grand_children = [child for child in parent.grandchild_set.all() for parent in grandparent.parent_set.all()] 

    for grand_child in grand_children: 
     if grand_child.name == self.name and grand_child != self: 
      raise IntegrityError("must be unique") 

但是,这给了IntegrityError

ValueError: "<GrandChild: name>" needs to have a value for field "grandchild" before this many-to-many relationship can be used. 
+0

从节约打电话时你为什么不能验证的唯一性方法?你可以说,如果一个祖父母包含一个父母,其中包含一个x,y,z属性的孙子,考虑到传递给这个孙子当前正在保存的数据,它将不是唯一的,所以拒绝 –

+0

我仍然遇到许多问题该实例不存在,但我需要该实例来测试唯一性。 –

回答

0
def save(self, *args, **kwargs): 
    grand_parent_id = kwargs.pop('grand_parent_id') 
    if grand_parent_id is None: 
     raise SomeException(...) 
    grand_parent = GrandParent.objects.get(pk=grand_parent_id) 
    for parent in grand_parent.parent_set.all(): 
     for grand_child in parent.grandchild_set.all(): 
      if grand_child.name == self.name: 
       raise IntegrityError("Name must be unique") 

# views.py 
grand_parent = get_object_or_404(GrandParent, pk=kwargs.get('grand_parent_pk')) 
if form.is_valid(): 
    form.save(grand_parent_id=grand_parent.pk) 
+0

我明白了这是如何工作的,但在这一点上,我正在尝试对模型进行单元测试(并没有开始实现视图)。我也想让它对除了视图以外的其他接口有效。 –

+0

我不认为你明白save()是如何工作的,它总是在模型创建时被调用。尝试执行'save(self,* args,** kwargs):raise ValidationError('Nope。')'并且执行'GrandChild.objects.create(name ='bob')',您将得到'ValidationError' ,视图只是对象创建最常用的接口之一,所以我向您展示了它是如何工作的。 您可以做 'GrandChild.objects.create(name ='bob',grand_parent_id = GrandParent.objects.filter(name ='foo')[0] .pk)'它也可以这样工作 –