Files
SecondBrain/90 Library/Programming/Python/Работа с формами и CUD.md
T
2026-06-05 13:29:15 +03:00

231 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
status: processing
type: concept
tags:
- django
- forms
- crud
- validation
- modelform
created: 2026-05-30
updated: 2026-06-05
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"})
}
```
В `ModelForm` модель и поля задаются во внутреннем классе `Meta`. `fields` показывает, какие поля модели попадут в форму. `exclude` можно использовать наоборот: указать, какие поля не включать.
---
## Жизненный цикл формы в представлении
Обычно 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_<fieldname>()`** — проверка одного конкретного поля.
- **`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
```
Для проверки связи между полями используют общий `clean()`. Например, "Пароль" и "Повтор пароля" нельзя нормально проверить через `clean_password()`, потому что нужно сравнить два поля.
---
## 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 }}` — быстро вывести поля формы в `<p>`.
- `{{ form.as_table }}` — вывести поля как строки таблицы.
- Ручное управление нужно, когда важна HTML-разметка, CSS-классы или отдельный вывод ошибок.
```html
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Сохранить</button>
</form>
```
```html
<form method="post">
{% csrf_token %}
{% for field in form %}
<div>
{{ field.label_tag }}
{{ field }}
{{ field.errors }}
</div>
{% endfor %}
<button type="submit">Сохранить</button>
</form>
```
### CSRF-токен
**CSRF (Cross-Site Request Forgery)** — атака, при которой чужой сайт пытается отправить запрос от имени уже авторизованного пользователя.
Пример: пользователь залогинен в Django-приложении. Он открывает вредную страницу, а она незаметно отправляет `POST`-запрос на удаление объекта. Без защиты браузер приложит cookies пользователя, и сервер может принять запрос как настоящий.
`{% csrf_token %}` добавляет в форму скрытое поле с защитным токеном:
```html
<input type="hidden" name="csrfmiddlewaretoken" value="...">
```
При `POST` Django сверяет токен из формы с токеном пользователя. Если токена нет или он неправильный, запрос отклоняется.
Короткое правило: во все HTML-формы с `method="post"` добавлять `{% csrf_token %}`.
## Простыми словами для экзамена
Форма Django делает три вещи:
1. Описывает поля.
2. Валидирует входные данные.
3. Даёт очищенные данные в `cleaned_data`.
Основные поля:
- `CharField` — строка;
- `IntegerField` — целое число;
- `BooleanField``True/False`;
- `ChoiceField` — выбор из списка;
- `EmailField` — email;
- `DateField` — дата;
- `FileField` — файл.
`widget` управляет HTML-представлением поля, а не типом данных. Например, строковое поле можно показать как пароль:
```python
password = forms.CharField(widget=forms.PasswordInput)
```
Подсказка к полю задаётся через `help_text`:
```python
email = forms.EmailField(help_text="Введите рабочую почту")
```
После `form.is_valid()`:
- `form.cleaned_data` содержит нормальные Python-значения;
- `form.errors` содержит ошибки;
- `form.save()` у `ModelForm` сохраняет объект модели.