I have a model with a ManyToManyField similar to this one (the model Word has a language, too):
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')
When trying to add a new sentence (e.g. through django admin) I get 'Sentence' instance needs to have a primary key value before a many-to-many relationship can be used
. This means I can't access self.words before saving it, but this is exactly what I'm trying to do. Is there any way to work around this so you can validate this model nevertheless? I really want to directly validate the model's fields.
I found many questions concerning this exception, but I couldn't find help for my problem. I would appreciate any suggestions!
It is not possible to do this validation in the model's clean
method, but you can create a model form which can validate the choice of words
.
from django import forms class SentenceForm(forms.ModelForm): class Meta: model = Sentence fields = ['words', 'language'] 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
You can then customise your Sentence
model admin class, to use your form in the Django admin.
class SentenceAdmin(admin.ModelAdmin): form = SentenceForm admin.register(Sentence, SentenceAdmin)
According to Django docs you can listen to the m2m_changed signal, which will trigger pre_add and post_add actions.
Using add() with a many-to-many relationship, however, will not call any save() methods (the bulk argument doesn’t exist), but rather create the relationships using QuerySet.bulk_create(). If you need to execute some custom logic when a relationship is created, listen to the m2m_changed signal, which will trigger pre_add and post_add actions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With