Что касается form.save(commit=False), что я упускаю?
Как объясняется во многих постах, например, в следующем: Зачем мы используем «form.save(commit=False)» в Django-views? «Основной вариант использования - если у вас есть форма ModelForm, которая не содержит всех необходимых полей модели. Вам нужно сохранить эту форму в базе данных, но поскольку вы не указали все необходимые поля, вы получите ошибку...», что все хорошо и замечательно, но почему бы просто не заполнить все поля экземпляра и затем вызвать обычное сохранение? В приведенном ниже примере:
# Creates a Dog class with all fields as mandatory:
class Dog(models.Model):
name = models.CharField(max_length=50)
race = models.CharField(max_length=50)
age = models.PositiveIntegerField()
# Creates a ModelForm with only name and age:
class DogForm(forms.ModelForm):
class Meta:
model = Dog
fields = ['name', 'age']
# In your view use this form:
def dog_view(request):
...
form = DogForm(request.POST or None)
# If the form is valid we need to add a race, otherwise we will get an error:
if form.is_valid():
dog = form.save(commit=False)
# Define the race here:
dog.race = 'Labrador retriever'
# And then do the regular save to push the change in the database:
dog.save()
...
почему бы просто не сказать:
form = DogForm(request.POST or None)
# Define the race:
dog.race = 'Labrador retriever'
if form.is_valid():
# Do the regular save:
dog.save()
Что я здесь упускаю?
это все хорошо и замечательно, но почему бы просто не заполнить все поля экземпляра, а затем вызвать обычное сохранение?
That is possible. In fact I recommend this approach in an article I wrote [django-antipatterns].
Но я бы посоветовал позволить форме управлять логикой, например:
def dog_view(request):
# …
form = DogForm(request.POST, request.FILES)
if form.is_valid():
form.instance.race = 'Labrador retriever'
form.save()
# …
Основная причина этого в том, что формы Django также могут сохранять многие-ко-многим поля, а значит, делать больше запросов к базе данных. Используя dog.save()
, вы сохраняете экземпляр собаки, и в этом случае все в порядке. Но если у вас есть ManyToManyField
с именем owners
, например. Таким образом, он больше не будет сохранять владельцев собаки.
Note: While most forms do not process media files, it is probably better to pass
request.FILES
[Django-doc] to the form anyway, such that if you later add an extra media field, all views that use the form will indeed handle the files properly.