Ответ 1
Формы - это просто инструмент для упрощения и ускорения процесса создания данных POST из запроса. Ручным способом было бы сделать request.POST.get('somefield')
для всех полей, которые есть в некоторой HTML-форме. Но Django может сделать лучше, чем это...
По сути, класс Form содержит несколько полей и выполняет следующие задачи:
- отображать входы HTML,
- собирать и проверять данные, когда пользователь отправляет их,
- Если поля не проверяются, возвращайте значения вместе с сообщениями об ошибках в HTML,
- Если все поля проверяются, укажите
form.cleaned_data
словарь как удобный способ доступа к этим значениям в представлении.
С этими значениями я мог бы вручную создать новый экземпляр MyModel
и сохранить его. Конечно, мне нужно было бы определить поле в форме для каждого поля в модели MyModel.
Это означает, что в основном я мог бы сделать что-то вроде этого:
(простите меня за то, что я не тестировал этот код, поэтому я не могу ручаться, что он на 100% правильный)
models.py:
class MyModel(models.Model):
field1 = models.CharField(max_length=40, blank=False, null=False)
field2 = models.CharField(max_length=60, blank=True, null=True)
forms.py:
class FormForMyModel(forms.Form):
form_field1 = forms.CharField(max_length=40, required=True)
form_field2 = forms.CharField(max_length=60, required=False)
views.py:
def create_a_my_model(request):
if request.method == 'POST':
form = FormForMyModel(request.POST)
if form.is_valid():
my_model = MyModel()
my_model.field1 = form.cleaned_data.get('form_field1', 'default1')
my_model.field2 = form.cleaned_data.get('form_field2', 'default2')
my_model.save()
else:
form = FormForMyModel()
context_data = {'form': form}
return HttpResponse('templtate.html', context_data)
(это может быть написано с несколькими строками кода меньше, но это должно быть как можно более ясным)
Обратите внимание, что нет никакой связи между полями модели и полями формы! Мы должны вручную назначать значения экземпляру MyModel при его создании.
В приведенном выше примере описывается общий рабочий процесс формы. Это часто необходимо в сложных ситуациях, но не в таком простом, как этот пример.
В этом примере (и много реальных примеров) Django может сделать лучше, чем это...
В приведенном выше примере вы можете заметить две неприятные проблемы:
- Я должен определять поля на
MyModel
и поля наFormForMyModel
отдельно. Тем не менее, существует много сходства между этими двумя группами (типами) полей, поэтому такая дублирующая работа. Сходство возрастает при добавлении меток, валидаторов и т.д. - Создание экземпляра
MyModel
немного глупо, нужно назначить все эти значения вручную.
Здесь находится ModelForm.
Они действуют в основном так же, как и обычная форма (на самом деле они расширены из обычных форм), но они могут спасти мне часть работы (две проблемы, которые я только что изложил, конечно:)).
Итак, вернемся к двум проблемам:
-
Вместо определения поля формы для каждого поля модели я просто определяю
model = MyModel
в классеMeta
. Это инструктирует форму автоматически генерировать поля формы из полей модели. -
Формы модели имеют доступный метод
save
. Это можно использовать для создания экземпляра модели в одной строке в представлении вместо того, чтобы вручную назначать поле за полем.
Итак, давайте сделаем пример выше с помощью ModelForm
:
models.py:
class MyModel(models.Model):
field1 = models.CharField(max_length=40, blank=False, null=False)
field2 = models.CharField(max_length=60, blank=True, null=True)
forms.py:
class MyModelForm(forms.ModelForm): # extending ModelForm, not Form as before
class Meta:
model = MyModel
views.py:
def create_a_my_model(request):
if request.method == 'POST':
form = MyModelForm(request.POST)
if form.is_valid():
# save the model to database, directly from the form:
my_model = form.save() # reference to my_model is often not needed at all, a simple form.save() is ok
# alternatively:
# my_model = form.save(commit=False) # create model, but don't save to database
# my.model.something = whatever # if I need to do something before saving it
# my.model.save()
else:
form = MyModelForm()
context_data = {'form': form}
return HttpResponse('templtate.html', context_data)
Надеемся, что это немного упростит использование форм Django.
Еще одно замечание - вполне нормально определять форму "Поля" на ModelForm
. Они не будут использоваться в form.save()
, но все равно могут быть доступны с помощью form.cleaned_data
, как в обычной форме.