--- status: processing type: concept tags: - django - forms - crud - validation - modelform created: 2026-05-30 updated: 2026-05-31 title: "Django: Работа с формами и CUD" source: - '[[lec5-django_cud_form.pdf]]' aliases: - 'Django: Формы и CUD' --- # Django: Работа с формами и CUD **CUD (Create, Update, Delete)** — операции изменения данных: создать, обновить, удалить. Форма в Django — это слой между HTML-формой и Python-кодом. Она принимает данные от пользователя, проверяет их, приводит к нормальным типам и помогает сохранить результат. ## Типы форм - **`forms.Form`** — обычная форма, не привязанная к модели. Подходит для поиска, обратной связи, фильтров, отправки email. - **`forms.ModelForm`** — форма на основе модели. Django сам создаёт поля формы по полям модели и умеет сохранять объект через `form.save()`. Если данные не нужно сохранять в таблицу напрямую — чаще подходит `forms.Form`. Если форма создаёт или редактирует модель — проще использовать `forms.ModelForm`. ```python from django import forms from .models import Blog class BlogForm(forms.ModelForm): class Meta: model = Blog fields = ["name", "tagline"] widgets = { "name": forms.TextInput(attrs={"class": "form-control"}) } ``` --- ## Жизненный цикл формы в представлении Обычно view работает так: 1. При `GET` создаёт пустую форму и показывает страницу. 2. При `POST` создаёт форму из `request.POST`. 3. Проверяет данные через `is_valid()`. 4. Если данные корректные — выполняет действие и делает `redirect`. 5. Если есть ошибки — снова показывает форму с ошибками. ```python from django.shortcuts import redirect, render def contact_view(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("success") else: form = ContactForm() return render(request, "contact.html", {"form": form}) ``` --- ## Валидация и очистка данных - **`is_valid()`** — запускает проверку формы. После него появляются `form.cleaned_data` и `form.errors`. - **Автоматическая очистка** — Django превращает строки из HTML-формы в Python-типы: число в `int`, дату в `date`, email в строку после проверки формата. - **`clean_()`** — проверка одного конкретного поля. - **`clean()`** — проверка всей формы, когда нужно сравнить несколько полей между собой. ```python from django import forms class RegisterForm(forms.Form): username = forms.CharField(max_length=50) password = forms.CharField(widget=forms.PasswordInput) password_repeat = forms.CharField(widget=forms.PasswordInput) def clean_username(self): username = self.cleaned_data["username"] if username.lower() == "admin": raise forms.ValidationError("Это имя нельзя использовать") return username def clean(self): cleaned_data = super().clean() password = cleaned_data.get("password") password_repeat = cleaned_data.get("password_repeat") if password and password_repeat and password != password_repeat: raise forms.ValidationError("Пароли не совпадают") return cleaned_data ``` --- ## Generic Editing Views (CBV для CUD) Django предоставляет готовые классы для типовых страниц редактирования: - **`CreateView`** — создать объект. - **`UpdateView`** — изменить объект; обычно ищет его по `pk` из URL. - **`DeleteView`** — удалить объект; требует подтверждения через `POST`. Главная идея: вместо ручной обработки `GET`, `POST`, `is_valid()` и `save()` можно описать модель, форму, шаблон и URL после успеха. ```python from django.urls import reverse_lazy from django.views.generic import CreateView, DeleteView, UpdateView from .forms import BlogForm from .models import Blog class BlogCreateView(CreateView): model = Blog form_class = BlogForm template_name = "blog/blog_form.html" success_url = reverse_lazy("blog_list") class BlogUpdateView(UpdateView): model = Blog form_class = BlogForm template_name = "blog/blog_form.html" success_url = reverse_lazy("blog_list") class BlogDeleteView(DeleteView): model = Blog template_name = "blog/blog_confirm_delete.html" success_url = reverse_lazy("blog_list") ``` ## Отображение в шаблоне - `{{ form.as_p }}` — быстро вывести поля формы в `

`. - `{{ form.as_table }}` — вывести поля как строки таблицы. - Ручное управление нужно, когда важна HTML-разметка, CSS-классы или отдельный вывод ошибок. ```html

{% csrf_token %} {{ form.as_p }}
``` ```html
{% csrf_token %} {% for field in form %}
{{ field.label_tag }} {{ field }} {{ field.errors }}
{% endfor %}
``` ### CSRF-токен **CSRF (Cross-Site Request Forgery)** — атака, при которой чужой сайт пытается отправить запрос от имени уже авторизованного пользователя. Пример: пользователь залогинен в Django-приложении. Он открывает вредную страницу, а она незаметно отправляет `POST`-запрос на удаление объекта. Без защиты браузер приложит cookies пользователя, и сервер может принять запрос как настоящий. `{% csrf_token %}` добавляет в форму скрытое поле с защитным токеном: ```html ``` При `POST` Django сверяет токен из формы с токеном пользователя. Если токена нет или он неправильный, запрос отклоняется. Короткое правило: во все HTML-формы с `method="post"` добавлять `{% csrf_token %}`.