Django ManyToMany模型验证

时间:2011-11-02 19:52:41

标签: django django-models

我有一个与此类似的ManyToManyField模型(模型Word也有一种语言):

class Sentence(models.Model):
    words = models.ManyToManyField(Word)
    language = models.ForeignKey(Language)
    def clean(self):
        for word in self.words.all():
            if word.language_id != self.language_id:
                raise ValidationError('One of the words has a false language')

当尝试添加新句子时(例如通过django admin),我得到'Sentence' instance needs to have a primary key value before a many-to-many relationship can be used。这意味着在保存之前我无法访问self.words,但这正是我想要做的。有没有办法解决这个问题,所以你可以验证这个模型吗?我真的想直接验证模型的字段。

我发现了很多关于此例外的问题,但我无法找到问题的帮助。我很感激任何建议!

3 个答案:

答案 0 :(得分:49)

在模型的clean方法中无法进行此验证,但您可以创建一个可以验证words选项的模型表单。

from django import forms

class SentenceForm(forms.ModelForm):
    class Meta:
        model = Sentence

    def clean(self):
        """
        Checks that all the words belong to the sentence's language.
        """
        words = self.cleaned_data.get('words')
        language = self.cleaned_data.get('language')
        if language and words:
            # only check the words if the language is valid
            for word in words:
                if words.language != language:
                    raise ValidationError("The word %s has a different language" % word)
        return self.cleaned_data

然后,您可以自定义Sentence模型管理员类,以便在Django管理员中使用您的表单。

class SentenceAdmin(admin.ModelAdmin):
    form = SentenceForm

admin.register(Sentence, SentenceAdmin)

答案 1 :(得分:1)

您无法通过模型上的clean方法执行此操作。在Django中M2M关系的工作方式根本不可能。但是,您可以对用于创建Sentence的表单进行此类验证,例如在管理员或您网站上的表单中。

答案 2 :(得分:0)

根据Django docs,您可以收听 m2m_changed 信号,该信号将触发 pre_add post_add 操作。

  

但是,使用具有多对多关系的add()不会调用任何save()方法(不存在bulk参数),而是使用QuerySet.bulk_create()创建关系。如果在创建关系时需要执行一些自定义逻辑,请收听m2m_changed信号,该信号将触发pre_add和post_add操作。