vault backup: 2026-05-31 10:23:48
This commit is contained in:
@@ -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 %}`.
|
||||
|
||||
Reference in New Issue
Block a user