Формы — один из важнейших инструментов в Django. До этого мы создавали «сырые» HTML-формы вручную, указывая <input>, <textarea>, <form method="post"> и т.д. Такой подход даёт базовое понимание механизма, но имеет существенные минусы:
- валидировать данные приходится вручную;
- нет автоматической генерации HTML-кода;
- ошибки валидации нужно писать самому;
- нет удобной привязки к полям модели;
- много однотипного кода.
Django решает эти проблемы с помощью встроенной системы форм.
Иногда нам нужно обрабатывать данные, не создавая запись в БД.
Несколько примеров из проекта cinemahub:
- форма поиска фильма;
- форма отправки отзыва (не сохраняем, а отправляем на email);
- форма фильтрации списка фильмов;
- форма проверки данных (например, поле «ваше имя» — просто для приветствия на сайте).
Для таких задач создаются обычные формы — классы, которые наследуются от forms.Form.
Эти формы можно использовать почти так же, как ModelForm, но они не создают и не обновляют записи в базе данных.
По договорённости Django-сообщества (и по лучшей практике) формы хранятся в файле:
your_app/
forms.py
В проекте cinemahub у нас есть приложение movies.
Поэтому создадим файл:
from django import formsЭтот файл будет хранить все формы, которые относятся к логике приложения movies.
Представим задачу: нужно сделать тестовую форму, которая собирает от пользователя информацию о фильме, но не сохраняет её в базу.
Например, мы хотим проверить, может ли студент корректно заполнить форму с минимальной валидацией.
from django import forms
class AddMovieSimpleForm(forms.Form):
title = forms.CharField(
max_length=255,
label="Название фильма"
)
year = forms.IntegerField(
min_value=1900,
max_value=2100,
label="Год выхода"
)
description = forms.CharField(
required=False,
widget=forms.Textarea,
label="Описание фильма"
)
is_featured = forms.BooleanField(
required=False,
label="Отображать на главной странице"
)Разберём поля:
CharField→ обычное текстовое поле.IntegerField→ Django автоматически проверяет, что это число.min_value/max_value→ границы значений — год не может быть 1450 или 3000.Textarea→ виджет для многострочного текста.BooleanField→ чекбокс.required=False→ поле необязательное.
Форма уже умеет:
- строить HTML;
- валидировать значения;
- показывать ошибки.
Мы создадим отдельное представление, которое:
- показывает форму при GET-запросе;
- принимает данные и валидирует их при POST-запросе;
- выводит результат.
from django.shortcuts import render
from .forms import AddMovieSimpleForm
def add_movie_simple_view(request):
result = None
if request.method == "POST":
form = AddMovieSimpleForm(request.POST)
if form.is_valid():
result = form.cleaned_data
else:
# Форма не прошла валидацию — Django сам покажет ошибки
pass
else:
form = AddMovieSimpleForm()
return render(request, "movies/add_movie_simple.html", {
"form": form,
"result": result,
})Что здесь происходит:
- Страница открылась → это GET → делаем пустую форму.
- Пользователь отправил форму → это POST → создаём форму с данными.
is_valid()запускает встроенную валидацию Django.- Если всё хорошо → результат лежит в
cleaned_data. - Ошибки Django выводит автоматически в шаблоне.
Формы Django выводятся автоматически — нам остаётся лишь подключить их в HTML.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<title>Учебная форма добавления фильма</title>
</head>
<body>
<h1>Учебная форма добавления фильма</h1>
<form action="" method="post">
{% csrf_token %} {{ form.as_p }}
<button type="submit">Отправить</button>
</form>
{% if result %}
<h2>Результат:</h2>
<pre>{{ result }}</pre>
{% endif %}
</body>
</html>{{ form.as_p }}— Django сам создаёт HTML<p>…</p>для каждого поля.- Ошибки валидации выводятся автоматически рядом с полем.
- Внизу мы выводим результат обработанных данных (
cleaned_data).
from django.urls import path
from .views import add_movie_simple_view
urlpatterns = [
path("add-simple/", add_movie_simple_view, name="add-movie-simple"),
]- Запускаем сервер:
python manage.py runserver
- Переходим:
http://localhost:8000/movies/add-simple/
- Заполняем форму.
- Нажимаем «Отправить».
🎉 Если всё заполнено корректно → внизу страницы появится:
{'title': 'Matrix', 'year': 1999, 'description': '...', 'is_featured': True}
❌ "Enter a whole number" — пользователь ввёл текст в поле year.
❌ "Ensure this value is less than or equal to 2100" — год слишком большой.
❌ Форма не отображается Проверь:
- что указал правильный путь к шаблону;
- что приложение
moviesесть вINSTALLED_APPS; - что URL включён в корневой
urls.py.
- Создать форму, которая принимает название фильма и жанр (строкой), а затем выводит их в результат.
- Создать форму с 1 полем:
year— число от 1900 до 2025. Если число корректное, выводить: "Вы выбрали год: X"
- Создать форму, которая принимает email и текст отзыва (textarea). Форма не должна ничего сохранять — просто выводить результат.
- Форма для названия фильма и жанра.
📄 movies/forms.py
class MovieGenreForm(forms.Form):
title = forms.CharField(max_length=255, label="Название фильма")
genre = forms.CharField(max_length=100, label="Жанр")📄 movies/views.py
def movie_genre_view(request):
result = None
if request.method == "POST":
form = MovieGenreForm(request.POST)
if form.is_valid():
result = form.cleaned_data
else:
form = MovieGenreForm()
return render(request, "movies/movie_genre.html", {
"form": form,
"result": result,
})📄 movies/templates/movies/movie_genre.html
<form method="post">
{% csrf_token %} {{ form.as_p }}
<button type="submit">Отправить</button>
</form>
{% if result %}
<p>{{ result.title }} — жанр: {{ result.genre }}</p>
{% endif %}- Форма с проверкой года.
📄 forms.py
class YearCheckForm(forms.Form):
year = forms.IntegerField(
min_value=1900,
max_value=2025,
label="Год"
)📄 views.py
def year_check_view(request):
result = None
if request.method == "POST":
form = YearCheckForm(request.POST)
if form.is_valid():
result = form.cleaned_data["year"]
else:
form = YearCheckForm()
return render(request, "movies/year_check.html", {
"form": form,
"result": result,
})📄 year_check.html
<form method="post">
{% csrf_token %} {{ form.as_p }}
<button>Проверить</button>
</form>
{% if result %}
<p>Вы выбрали год: {{ result }}</p>
{% endif %}- Форма для вывода результата текста и email.
📄 forms.py
class FeedbackForm(forms.Form):
email = forms.EmailField(label="Ваш email")
message = forms.CharField(widget=forms.Textarea, label="Сообщение")📄 views.py
def feedback_view(request):
result = None
if request.method == "POST":
form = FeedbackForm(request.POST)
if form.is_valid():
result = form.cleaned_data
else:
form = FeedbackForm()
return render(request, "movies/feedback.html", {
"form": form,
"result": result,
})📄 feedback.html
<form method="post">
{% csrf_token %} {{ form.as_p }}
<button>Отправить</button>
</form>
{% if result %}
<p>Email: {{ result.email }}</p>
<p>Сообщение: {{ result.message }}</p>
{% endif %}- Чем форма
forms.Formотличается от ModelForm? - Где правильно хранить формы в Django-проекте?
- Что делает метод
is_valid()? - Какие данные находятся в
form.cleaned_data? - Что произойдёт, если убрать
{% csrf_token %}? - Как Django выводит ошибки валидации?
- Что делает атрибут
required=False? - Для чего используются виджеты (
Textarea,CheckboxInputи т.д.)?