Функция inlineformset_factory
Функция inlineformset_factory применяется для создания формсета, который позволяет одновременно редактировать несколько объектов дочерней модели, связанных с одним родительским объектом через внешний ключ. Эта функция возвращает класс формсета, который наследуется от BaseInlineFormSet и предоставляет удобный интерфейс для работы с связанными данными. Основные параметры функции включают родительскую модель, дочернюю модель, количество дополнительных пустых форм и максимальное количество форм.
Синтаксис
from django.forms import inlineformset_factory
InlineFormSet = inlineformset_factory(
parent_model,
model,
form=ModelForm,
formset=BaseInlineFormSet,
fk_name=None,
fields=None,
exclude=None,
extra=3,
can_delete=True,
can_order=False,
max_num=None,
min_num=None,
validate_max=False,
validate_min=False,
absolute_max=None,
can_delete_extra=True,
renderer=None,
widgets=None,
localized_fields=None,
labels=None,
help_texts=None,
error_messages=None,
field_classes=None,
factory_kwargs=None,
)
Обязательными аргументами являются parent_model и model. Все остальные параметры опциональны и позволяют гибко настраивать поведение формсета.
Пример
Рассмотрим простой пример работы с inlineformset_factory. У нас есть модели Author и Book, где книга связана с автором через внешний ключ. Создадим формсет для редактирования книг конкретного автора:
from django.db import models
from django.forms import inlineformset_factory
from myapp.models import Author, Book
# Модели
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
# Создаём формсет для модели Book с привязкой к Author
BookFormSet = inlineformset_factory(
Author,
Book,
fields=['title'],
extra=2,
can_delete=True
)
# Получаем автора из базы данных
author = Author.objects.get(pk=1)
# Создаём формсет с данными существующего автора
formset = BookFormSet(instance=author)
# Выводим количество форм в формсете
print(f"Number of forms: {len(formset)}")
Результат выполнения кода:
"Number of forms: 3"
В результате мы получили формсет, который содержит две дополнительные пустые формы для добавления новых книг и одну форму для существующей книги автора. Всего три формы.
Пример
Теперь рассмотрим, как обрабатывать данные, переданные методом POST, в представлении. Используем те же модели и формсет для сохранения изменённых данных:
from django.shortcuts import render, redirect
from django.forms import inlineformset_factory
from myapp.models import Author, Book
def edit_author_books(request, author_id):
author = Author.objects.get(pk=author_id)
BookFormSet = inlineformset_factory(
Author,
Book,
fields=['title'],
extra=2,
can_delete=True
)
if request.method == 'POST':
formset = BookFormSet(request.POST, instance=author)
if formset.is_valid():
formset.save()
return redirect('author_detail', author_id=author.id)
else:
formset = BookFormSet(instance=author)
return render(request, 'edit_books.html', {'formset': formset})
В этом примере при GET-запросе мы создаём формсет с данными автора. При POST-запросе передаём данные в формсет, проверяем их валидность и сохраняем. Метод save формсета автоматически обработает создание, обновление и удаление связанных объектов в зависимости от переданных данных.
Пример
Функция inlineformset_factory позволяет указать, какие поля дочерней модели должны отображаться в формах. Рассмотрим случай, когда нужно исключить некоторые поля или использовать кастомную форму:
from django import forms
from django.forms import inlineformset_factory
from myapp.models import Author, Book
# Кастомная форма для книги
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = ['title', 'publication_year']
def clean_title(self):
title = self.cleaned_data.get('title')
if len(title) < 3:
raise forms.ValidationError("Title is too short!")
return title
# Создаём формсет с кастомной формой
BookFormSet = inlineformset_factory(
Author,
Book,
form=BookForm,
extra=1,
can_delete=False,
max_num=5
)
author = Author.objects.get(pk=1)
formset = BookFormSet(instance=author)
# Получаем словари с данными форм
for form in formset:
print(form.cleaned_data if form.is_valid() else "Invalid form")
Результат выполнения кода для валидных форм:
"{'title': 'Django for Beginners', 'publication_year': 2023}"
"{'title': 'Advanced Django', 'publication_year': 2024}"
"{'title': '', 'publication_year': None}"
В этом примере мы использовали кастомную форму с валидацией поля title и установили ограничение на максимальное количество форм до пяти. Параметр can_delete отключён, поэтому удаление записей через формсет недоступно.
Смотрите также
-
функция
modelformset_factory,
которая создаёт формсет для модели без привязки к родительскому объекту -
функция
formset_factory,
которая создаёт формсет из обычных форм Django -
класс
save,
который сохраняет данные формы модели в базу данных -
атрибут
instance,
который связывает форму с конкретным объектом модели