Где я должен установить поля модели, производные от поля формы?
Если модель имеет некоторые поля, которые не отображаются непосредственно на поля ModelForm
, где я должен установить их значение? Далее, form.blast_db
должен быть присвоен либо model.protein_db
, либо model.nucleotide_db
в зависимости от того, какой это тип взрывной БД. Они являются взаимоисключающими, но необходимыми, поэтому должны быть установлены до вызова model.full_clean()
.
from django.db import models
class BlastQuery(models.Model):
# Protein/nucleotide blast DB. Mutually exclusive, one must be provided
protein_db = models.ForeignKey(ProteinDB, null=True, blank=True)
nucleotide_db = models.ForeignKey(ProteinDB, null=True, blank=True)
# Just 1 field to keep it terse but in reality there are many other fields
foo = models.IntegerField()
def clean(self):
if self.protein_db and self.nucleotide_db:
raise ValidationError('Protein/nucleotide DB are mutually exclusive')
if not self.protein_db and not self.nucleotide_db:
raise ValidationError('Protein/nucleotide DB are required')
from django import forms
class BlastForm(forms.ModelForm):
# Magical field that's like a ModelChoiceField but can
# hold both ProteinDB and NucleotideDB instances
blast_db = BlastDBField()
class Meta:
model = BlastQuery
fields = ('foo',)
Вы можете установить производные поля в Form.clean
:
class BlastForm(forms.ModelForm):
# ...
def clean(self):
super().clean()
# Validate/modify self.cleaned_data
# ...
# Derive the protein/nucleotide db field
blast_db = self.cleaned_data.get('blast_db')
if blast_db:
if blast_db.type == 'protein':
self.instance.protein_db = blast_db
else:
self.instance.nucleotide_db = blast_db
ModelForm
обновляет self.instance
с self.cleaned_data
после form.clean()
(в _post_clean
) и вызывает model.full_clean()
, поэтому если бы вы изменили self.instance
в form.save()
, вы бы опоздали, чтобы предотвратить ошибку валидации. Также обратите внимание, что только Meta.fields
, которые не появляются в Meta.exclude
, применяются от self.cleaned_data
к self.instance
, поэтому установка protein_db
/nucleotide_db
в self.cleaned_data
тоже ничего не даст. Вы можете переопределить Model.clean_fields(exclude) вместо Model.clean
и пропустить проверку protein_db
и nucleotide_db
, когда они находятся в exclude
, но тогда они никогда не будут проверены, если вы не вызовете form.full_clean()
снова перед сохранением. Поэтому просто поместите его в Form.clean
, так как он не имеет этих недостатков.