vault backup: 2026-05-31 10:23:48

This commit is contained in:
Dmitry
2026-05-31 10:23:49 +03:00
parent f15f5e29f2
commit 9f1ed9ce7e
3 changed files with 148 additions and 47 deletions
+15 -16
View File
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
---
status: seed
status: processing
type: concept
tags:
- django
@@ -9,79 +9,182 @@ tags:
- 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 предоставляет мощную подсистему форм для их реализации.
# Django: Работа с формами и CUD
**CUD (Create, Update, Delete)** — операции изменения данных: создать, обновить, удалить.
Форма в Django — это слой между HTML-формой и Python-кодом. Она принимает данные от пользователя, проверяет их, приводит к нормальным типам и помогает сохранить результат.
## Типы форм
1. **`forms.Form`**: Для общих задач (поиск, обратная связь), не привязанных к моделям.
2. **`forms.ModelForm`**: Автоматическая генерация полей на основе модели.
- **`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']
fields = ["name", "tagline"]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'})
"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():
# Данные очищены и доступны в form.cleaned_data
data = form.cleaned_data
# Действие (сохранение или отправка email)
return redirect('success')
send_email(data["email"], data["message"])
return redirect("success")
else:
form = ContactForm()
return render(request, 'contact.html', {'form': form})
return render(request, "contact.html", {"form": form})
```
---
## Валидация и очистка данных
- **`is_valid()`**: Запускает процесс проверки.
- **Автоматическая очистка**: Превращает текст в типы Python (например, строку в `datetime`).
- **`clean_<fieldname>()`**: Валидация конкретного поля.
- **`clean()`**: Валидация всей формы (сравнение полей).
- **`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
```
---
## Generic Editing Views (CBV для CUD)
Django предоставляет готовые классы для CRUD:
- **CreateView**: Создание объекта.
- **UpdateView**: Редактирование (требует `pk` в URL).
- **DeleteView**: Удаление (требует подтверждения через POST).
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')
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 }}` — в строках таблицы.
- **Ручное управление:**
- `{{ form.as_p }}`быстро вывести поля формы в `<p>`.
- `{{ form.as_table }}` — вывести поля как строки таблицы.
- Ручное управление нужно, когда важна HTML-разметка, CSS-классы или отдельный вывод ошибок.
```html
{% for field in form %}
{{ field.label_tag }} {{ field }}
{{ field.errors }}
{% endfor %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Сохранить</button>
</form>
```
*Важно:* Не забывайте про `{% csrf_token %}` внутри тега `<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 %}`.
+1 -2
View File
@@ -523,7 +523,7 @@ total: 467
|---------|---------|--------|------|------|
| [[Django: Модели и ORM]] | Django Модели и ORM | processing | concept | [django, backend, orm, database, migrations] |
| [[Django: Представления, шаблоны и CBV]] | Django: Представления, шаблоны и CBV | processing | concept | [django, routing, templates, cbv, fbv] |
| [[Django: Работа с формами и CUD]] | Django: Формы и CUD | seed | concept | [django, forms, crud, validation, modelform] |
| [[Django: Работа с формами и CUD]] | Django: Формы и CUD | processing | concept | [django, forms, crud, validation, modelform] |
| [[Python - MOC]] | Python - MOC | seed | moc | [programming, python] |
| [[Python: Базовый синтаксис и основы]] | Основы Python | seed | concept | [python, syntax, programming-basics, functional-programming] |
| [[Курс по Python и Django]] | Курс по Python и Django | seed | moc | [python, django, backend] |
@@ -767,4 +767,3 @@ total: 467
| [[Daily Note]] | — | — | daily | [daily] |
| [[Study Item]] | — | seed | knowledge | [] |
| [[Travel Item]] | — | seed | knowledge | [travel] |