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