
Формы являются одной из самых вкусных вещей в Django (после моделей, админки, url-маршрутизации и т.д.). Перед вами небольшое, но ёмкое руководство по их использованию, представляющее собой разбор 8 часто встречающихся ситуаций при программировании форм.
- Задача. Проверка и отображение простейшей формы.
Copy Source | Copy HTML
class UserForm(forms.Form):
username = forms.CharField()
joined_on = forms.DateField()
Этот код отвечает за отображение двух текстовых полей, за данные, которые содержатся в них, а так же за корректность введенной даты.
>
- Задача. Создание формы, значения которой зависят от какого-то конкретного параметра. Например, вам может потребоваться отобразить значения, относящиеся к определённому субдомену.
Copy Source | Copy HTML
class UserForm(forms.Form):
username = forms.CharField()
plan = forms.ModelChoiceField(queryset = Plan.objects.none())
def __init__(self, subdomain, *args, **kwargs):
self.default_username = default_username
super(UserForm, self).__init__(*args, **kwargs)
self.fields['plan'].queryset = Plan.objects.filter(subdomain = subdomain)
Здесь в методе __init__ мы переопределяем стандартный queryset поля plan. Подобным образом можно переопределять абсолютно любые атрибуты.Внимательный читательЗаметим также, что выборка происходит лишь после вызова super(UserForm, self).__init__(*args, **kwargs).
>
- Задача. Многократное использование формы. Обработка данных с помощью cleaned_data.
Copy Source | Copy HTML
class UserForm(forms.Form):
username = forms.CharField()
def save(self):
data = self.cleaned_data
user = User.objects.create(username = data['username'])
#create a profile
UserProfile.objects.create(user = user, ...some more data...)
Вы можете назвать этот метод как угодно, но обычно его называют save, чтобы сохранить сходство с ModelForm.
>
- Задача. Создание формы с полями, которые имеют собственный вид проверки.
Copy Source | Copy HTML
class UserForm(forms.Form):
username = forms.CharField()
def clean_username(self):
data = self.cleaned_data
try:
User.objects.get(username = data['username'])
except User.DoesNotExist:
return data['username']
raise forms.ValidationError('This username is already taken.')
Здесь идёт проверка на уникальность имени пользователя.
>
- Задача. Создание формы с перекрёстной проверкой полей.
Copy Source | Copy HTML
class UserForm(forms.Form):
username = forms.CharField()
password1 = forms.PasswordField()
password2 = forms.PasswordField()
def clean(self):
data = self.cleaned_data
if "password1" in data and "password2" in data and data["password1"] != data["password2"]:
raise forms.ValudationError("Passwords must be same")
Пароли в двух полях проверяются на идентичность друг другу.
>
- Задача. Создание формы, поля которой зависят от некого значения в базе данных. Например, вам может потребоваться отображать разные формы для разных пользователей.
Copy Source | Copy HTML
def get_user_form_for_user(user):
class UserForm(forms.Form):
username = forms.CharField()
fields = user.get_profile().all_field()
#Use field to find what to show.
Выходом в данном случае будет — создавать форму динамически.
>
- Задача. Создание HTML формы, работающей с несколькими моделями.
Copy Source | Copy HTML
#in forms.py
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ["username", "email"]
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
#in views.py
def add_user(request):
...
if request.method == "POST":
uform = UserForm(data = request.POST)
pform = UserProfileForm(data = request.POST)
if uform.is_valid() and pform.is_valid():
user = uform.save()
profile = pform.save(commit = False)
profile.user = user
profile.save()
....
...
#in template
<form method="post">
{{ uform.as_p }}
{{ pform.as_p }}
<input type="submit" ...>
</form>
>
- Задача. Использование нескольких форм одного типа на одной странице. Например, при создании опроса вам может понадобиться отобразить все вопросы на одной странице.
Copy Source | Copy HTML
#IN views.py
def survey(request, survey_slug)
...
questions = survey.questions.all()
question_forms = []
for question in questions:
qform = QuestionForm(question=question, prefix = question.slug)
question_forms.append(qform)
...
if request.method == "POST":
for question in questions:
qform = QuestionForm(question=question, prefix = question.slug, data = request.POST)
#Validate and do save action
...
...
В этой ситуации нам очень поможет атрибут prefix.
Подробнее о формах, разумеется, вы можете прочитать в документации.



комментарии (33)