Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
ModelForm в Django
ModelForm — это один из самых мощных инструментов Django, который автоматически создаёт HTML-форму на основе модели базы данных. Это экономит тонны кода и делает разработку быстрой.
Суть проблемы, которую решает ModelForm
Представь, что у тебя есть модель User в базе данных:
from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
age = models.IntegerField()
bio = models.TextField()
is_active = models.BooleanField(default=True)
Без ModelForm пришлось бы писать форму вручную:
from django import forms
class UserForm(forms.Form):
name = forms.CharField(max_length=100, required=True)
email = forms.EmailField(required=True)
age = forms.IntegerField(required=True)
bio = forms.CharField(widget=forms.Textarea)
is_active = forms.BooleanField(required=False)
Это дублирование! Те же поля описаны дважды. ModelForm решает эту проблему.
Базовое использование ModelForm
from django import forms
from .models import User
class UserModelForm(forms.ModelForm):
class Meta:
model = User
fields = ['name', 'email', 'age', 'bio', 'is_active']
Вот и всё! Django автоматически:
- Создаст поля формы на основе типов полей модели
- Применит валидацию
- Установит правильные виджеты (текстовое поле, textarea и т.д.)
Использование в представлении (View)
from django.shortcuts import render, redirect, get_object_or_404
from django.views import View
from .models import User
from .forms import UserModelForm
# Функциональное представление
def create_user(request):
if request.method == 'POST':
form = UserModelForm(request.POST)
if form.is_valid():
form.save() # Автоматически сохранит в БД!
return redirect('user_list')
else:
form = UserModelForm()
return render(request, 'create_user.html', {'form': form})
# Или обновление
def update_user(request, user_id):
user = get_object_or_404(User, id=user_id)
if request.method == 'POST':
form = UserModelForm(request.POST, instance=user)
if form.is_valid():
form.save()
return redirect('user_detail', user_id=user_id)
else:
form = UserModelForm(instance=user) # Заполняет форму текущими данными
return render(request, 'edit_user.html', {'form': form, 'user': user})
Обрати внимание на form.save() — это сохраняет данные прямо в БД!
В шаблоне (HTML)
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Сохранить</button>
</form>
Django автоматически отрендерит все поля с правильными типами input.
Кастомизация ModelForm
class UserModelForm(forms.ModelForm):
# Добавляем кастомное поле
subscribe = forms.BooleanField(
required=False,
label="Подписаться на новости"
)
class Meta:
model = User
fields = ['name', 'email', 'age', 'bio']
labels = {
'name': 'Полное имя',
'email': 'Email адрес',
}
widgets = {
'name': forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Введи имя'
}),
'bio': forms.Textarea(attrs={
'rows': 4,
'class': 'form-control'
}),
}
help_texts = {
'age': 'Должно быть от 18 до 120 лет'
}
def clean_age(self):
age = self.cleaned_data.get('age')
if age and (age < 18 or age > 120):
raise forms.ValidationError("Возраст должен быть от 18 до 120")
return age
def clean_email(self):
email = self.cleaned_data.get('email')
# Проверяем, что email уникален (исключая текущий объект)
if User.objects.filter(email=email).exclude(pk=self.instance.pk).exists():
raise forms.ValidationError("Этот email уже используется")
return email
Что такое cleaned_data?
Это словарь валидированных и очищенных данных:
def create_user(request):
if request.method == 'POST':
form = UserModelForm(request.POST)
if form.is_valid():
# cleaned_data содержит безопасные данные
print(form.cleaned_data) # {'name': '...', 'email': '...', ...}
form.save()
Выбор полей: fields vs exclude
class Meta:
model = User
# Вариант 1: явно указываем какие поля
fields = ['name', 'email', 'bio']
class Meta:
model = User
# Вариант 2: исключаем ненужные поля
exclude = ['created_at', 'updated_at', 'is_staff']
Лучше использовать fields, потому что это явно показывает, какие поля редактируются.
Сохранение с доп. обработкой
def create_user(request):
if request.method == 'POST':
form = UserModelForm(request.POST)
if form.is_valid():
user = form.save(commit=False) # Не сохраняем ещё в БД
user.created_by = request.user # Добавляем текущего пользователя
user.save() # Теперь сохраняем
return redirect('user_detail', user_id=user.id)
Класс-представление (Class-Based View)
Django предоставляет встроенные CBV для ModelForm:
from django.views.generic import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import User
from .forms import UserModelForm
class UserCreateView(CreateView):
model = User
form_class = UserModelForm
template_name = 'create_user.html'
success_url = reverse_lazy('user_list')
class UserUpdateView(UpdateView):
model = User
form_class = UserModelForm
template_name = 'edit_user.html'
pk_url_kwarg = 'user_id'
success_url = reverse_lazy('user_list')
Even better! Django сам обработает POST и GET запросы.
Валидация на разных уровнях
class UserModelForm(forms.ModelForm):
class Meta:
model = User
fields = ['email']
# Валидация отдельного поля
def clean_email(self):
email = self.cleaned_data.get('email')
if not email.endswith('@company.com'):
raise forms.ValidationError("Используй корпоративный email")
return email
# Валидация всей формы (несколько полей)
def clean(self):
cleaned_data = super().clean()
password = cleaned_data.get('password')
password_confirm = cleaned_data.get('password_confirm')
if password != password_confirm:
raise forms.ValidationError("Пароли не совпадают")
return cleaned_data
Ошибки в форме
<form method="post">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert">
{{ form.non_field_errors }}
</div>
{% endif %}
{% for field in form %}
<div>
{{ field.label_tag }}
{{ field }}
{% if field.errors %}
<span class="error">{{ field.errors }}</span>
{% endif %}
</div>
{% endfor %}
<button type="submit">Сохранить</button>
</form>
Преимущества ModelForm
- Автоматическая валидация — используется валидация модели
- Меньше кода — не нужно писать поля вручную
- Синхронизация — если модель меняется, форма автоматически обновляется
- Встроенное сохранение — form.save() сохраняет прямо в БД
- Интеграция с моделью — работает с отношениями (ForeignKey, ManyToMany)
Работа с отношениями
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(User, on_delete=models.CASCADE)
tags = models.ManyToManyField(Tag)
class PostModelForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'author', 'tags']
Django автоматически создаст выпадающий список для author и мультиселект для tags!
Вывод
ModelForm — это must-have инструмент в Django. Он экономит кучу кода, обеспечивает валидацию и делает код более maintainable. Правильное использование ModelForm — признак опытного Django-разработчика.