Формы Django: валидация и cleaned_data
Формы — главный канал данных от пользователя к серверу. Django Forms берут на себя самое опасное: отрисовку, валидацию и очистку ввода.
Суть: класс Form описывает поля, Django сам рисует HTML, проверяет данные методом is_valid() и складывает очищенные значения в cleaned_data. Это защита от мусора и атак.
Зачем не писать формы руками
Можно собирать данные из request.POST вручную, но это путь к багам и уязвимостям: забыли проверить тип, не экранировали ввод, пропустили обязательное поле. Django Forms решают всё это декларативно. Вы описываете поля как класс, а фреймворк рисует HTML, валидирует ввод и возвращает чистые данные.
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)
agree = forms.BooleanField(required=True)
Поток валидации
Форма работает в две стороны. На GET вы создаёте пустую форму и рисуете её. На POST — создаёте форму с данными и валидируете:
def contact(request):
if request.method == "POST":
form = ContactForm(request.POST)
if form.is_valid():
data = form.cleaned_data # чистые, проверенные данные
send_email(data["email"], data["message"])
return redirect("thanks")
else:
form = ContactForm()
return render(request, "contact.html", {"form": form})
Полный поток данных формы:
POST-данные (request.POST)
│
▼
ContactForm(request.POST)
│
▼
form.is_valid() ──┬── False ─▶ form.errors → перерисовать форму
│ с сообщениями об ошибках
└── True ─▶ form.cleaned_data → сохранить/обработать
│
▼
redirect
cleaned_data и errors
После is_valid() очищенные и приведённые к типам данные лежат в form.cleaned_data (словарь). Если валидация не прошла, ошибки — в form.errors, и форму перерисовывают с подсветкой проблем. В шаблоне форму выводят так:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Отправить</button>
</form>
Тег {% csrf_token %} обязателен для всех POST-форм — без него Django отклонит запрос (защита от CSRF, об этом следующий урок).
Кастомная валидация
Для проверки одного поля пишут метод clean_<имя>, для проверки нескольких полей вместе — общий clean. При нарушении бросают ValidationError:
def clean_name(self):
name = self.cleaned_data["name"]
if "admin" in name.lower():
raise forms.ValidationError("Имя admin запрещено")
return name
Как это работает под капотом
Валидация — это последовательный прогон значений через набор проверок с накоплением ошибок. Это языко-независимая логика, которую видно на чистом Python:
# Попробуй сам ▶ — движок валидации формы
def validate(data):
errors, cleaned = {}, {}
# обязательные поля
for field in ("name", "email", "message"):
if not data.get(field):
errors.setdefault(field, []).append("Обязательное поле")
# тип email
email = data.get("email", "")
if email and "@" not in email:
errors.setdefault("email", []).append("Некорректный email")
# своя проверка clean_name
if "admin" in data.get("name", "").lower():
errors.setdefault("name", []).append("Имя admin запрещено")
# собираем cleaned_data только если ошибок нет
if not errors:
cleaned = {k: v.strip() for k, v in data.items()}
return (len(errors) == 0), cleaned, errors
for sample in [
{"name": "Анна", "email": "[email protected]", "message": "Привет"},
{"name": "admin", "email": "плохой", "message": ""},
]:
ok, cleaned, errors = validate(sample)
print("is_valid:", ok)
print(" cleaned_data:", cleaned)
print(" errors:", errors)
Django делает то же: прогоняет встроенные проверки полей, затем ваши clean_*, накапливает ошибки в form.errors и заполняет cleaned_data только при успехе.
Частые ошибки
- Забыть {% csrf_token %}. POST-форма будет отклонена с ошибкой 403.
- Читать request.POST напрямую вместо cleaned_data. Сырые данные не проверены и не приведены к типам.
- Не вызвать is_valid() перед доступом к cleaned_data. Его там ещё нет.
- В clean-методе не вернуть значение.
clean_<поле>обязан вернуть очищенное значение.
Best practices
- Всегда работайте с
cleaned_data, а не с сырымrequest.POST. - Логику валидации держите в форме (
clean_*/clean), а не во view. - Не забывайте
{% csrf_token %}в каждой POST-форме. - Для полей, связанных с моделью, используйте ModelForm (следующий урок).
Итоги
Django Forms описывают поля декларативно, сами рисуют HTML и валидируют ввод. is_valid() проверяет данные, cleaned_data отдаёт чистые значения, errors — проблемы. Кастомные проверки — в методах clean. Это защищает приложение от мусора и атак. Дальше свяжем формы с моделями через ModelForm.