Функция modelformset_factory
Функция modelformset_factory применяется для динамического создания класса набора форм, связанного с моделью Django. Она принимает модель и набор параметров, возвращая класс BaseModelFormSet. Полученный набор форм позволяет обрабатывать несколько экземпляров модели в одной форме, что удобно для массового редактирования, добавления или удаления записей. В отличие от обычных форм, где работа идет с одной записью, набор форм дает возможность изменять сразу несколько объектов.
Основные параметры функции:
-
model- модель Django, на основе которой создаются формы; -
fields- список полей модели, которые будут включены в формы; -
exclude- список полей, которые нужно исключить из форм; -
extra- количество дополнительных пустых форм для добавления новых записей (по умолчанию1); -
max_num- максимальное количество форм в наборе; -
min_num- минимальное количество форм в наборе; -
validate_max- флаг, определяющий, нужно ли проверять максимальное количество форм; -
validate_min- флаг, определяющий, нужно ли проверять минимальное количество форм; -
form- пользовательский класс формы (по умолчаниюModelForm); -
formset- пользовательский класс набора форм (по умолчаниюBaseModelFormSet); -
widgets- словарь виджетов для полей формы; -
localized_fields- список полей, которые должны быть локализованы; -
labels- словарь для переопределения меток полей; -
help_texts- словарь для переопределения подсказок полей; -
error_messages- словарь для переопределения сообщений об ошибках; -
can_delete- флаг, добавляющий флажок для удаления объектов.
Все параметры передаются в виде именованных аргументов, при этом обязательными являются только model и хотя бы один из параметров fields или exclude.
Синтаксис
from django.forms import modelformset_factory
ModelFormSet = modelformset_factory(
model,
fields='__all__',
extra=1,
max_num=None,
min_num=None,
can_delete=False
)
Пример
Допустим, у нас есть модель Article для статей. Создадим набор форм для редактирования заголовков и статусов статей:
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
status = models.CharField(max_length=20)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Создадим набор форм и выведем формы для всех существующих статей:
from django.forms import modelformset_factory
from myapp.models import Article
ArticleFormSet = modelformset_factory(
model=Article,
fields=['title', 'status']
)
queryset = Article.objects.all()
formset = ArticleFormSet(queryset=queryset)
for form in formset:
print(form.instance.title, form.instance.status)
Результат выполнения кода:
"article 1 published"
"article 2 draft"
"article 3 published"
Пример
Набор форм удобно использовать для массового обновления данных. Создадим набор форм с возможностью добавления новых статей и удаления существующих:
from django.forms import modelformset_factory
from myapp.models import Article
ArticleFormSet = modelformset_factory(
model=Article,
fields=['title', 'status'],
extra=2,
can_delete=True,
max_num=10
)
queryset = Article.objects.filter(status='draft')
formset = ArticleFormSet(queryset=queryset)
if formset.is_valid():
instances = formset.save()
print(f"Saved {len(instances)} articles")
else:
print("Formset is not valid")
Результат выполнения кода:
"Saved 2 articles"
Пример
Используем пользовательскую форму и переопределим поведение набора форм для кастомной валидации:
from django import forms
from django.forms import modelformset_factory
from myapp.models import Article
class CustomArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'status']
def clean_title(self):
title = self.cleaned_data.get('title')
if len(title) < 3:
raise forms.ValidationError("Title is too short")
return title
class CustomArticleFormSet(forms.BaseModelFormSet):
def clean(self):
super().clean()
titles = []
for form in self.forms:
if form.cleaned_data and 'title' in form.cleaned_data:
title = form.cleaned_data['title']
if title in titles:
raise forms.ValidationError(
"Duplicate titles are not allowed"
)
titles.append(title)
ArticleFormSet = modelformset_factory(
model=Article,
form=CustomArticleForm,
formset=CustomArticleFormSet,
extra=1,
can_delete=True
)
queryset = Article.objects.all()
formset = ArticleFormSet(queryset=queryset)
if formset.is_valid():
formset.save()
print("All articles saved successfully")
else:
print("Formset errors:", formset.errors)
Результат выполнения кода:
"All articles saved successfully"
Смотрите также
-
функция
formset_factory,
которая создает набор форм на основе обычной формы -
функция
inlineformset_factory,
которая создает набор форм для работы с внешними ключами -
класс
ModelForm,
который используется для создания форм на основе моделей -
метод
save,
который сохраняет данные формы в базу данных