Django ManyToMany模型验证

pur*_*tic 37 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')
Run Code Online (Sandbox Code Playgroud)

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

我发现了很多关于这个例外的问题,但我无法找到解决问题的方法.我很感激任何建议!

Ala*_*air 51

在模型的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
Run Code Online (Sandbox Code Playgroud)

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

class SentenceAdmin(admin.ModelAdmin):
    form = SentenceForm

admin.register(Sentence, SentenceAdmin)
Run Code Online (Sandbox Code Playgroud)

  • 令人遗憾的是,没有可能直接在模型中验证它.但到目前为止,定制的ModelForm对我来说已经足够了.谢谢您的回答! (8认同)

M.V*_*oid 5

根据 Django文档,您可以收听m2m_changed信号,这将触发pre_addpost_add操作。

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