Чтобы понять, зачем нам нужны inline-формы, представьте себе ситуацию. У нас есть модель Автор и модель Книга. Каждая книга связана с автором через внешний ключ author. При создании нового автора мы хотим ввести также информацию о его книгах. Вместо того, чтобы создавать форму для автора, а затем отдельно формы для каждой книги, мы можем встроить форму для Книг прямо в форму для Автора. Это и есть inline-форма.
Django предоставляет удобный инструмент для реализации подобных задач — inline formsets. Inline-формы работают на основе связей моделей (ForeignKey и OneToOne) и позволяют легко добавлять, редактировать или удалять связанные записи.
Основные случаи использования inline-форм
Inline-формы особенно полезны, когда необходимо:
- Управлять связанными объектами прямо из основной формы (например, книги автора, заказ клиента или комментарии под постом).
- Упростить интерфейс для пользователя, исключив необходимость перехода между несколькими формами.
- Убедиться, что данные для связанных моделей обрабатываются атомарно (либо сохраняются все данные, либо ничего).
Шаг 1: Подготовка моделей
Для демонстрации мы создадим проект с двумя моделями: Author (автор) и Book (книга). Каждая книга связана с определенным автором ForeignKey.
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
publish_date = models.DateField()
author = models.ForeignKey(Author, related_name='books', on_delete=models.CASCADE)
def __str__(self):
return self.title
Здесь:
- Author — модель для хранения информации об авторе.
- Book — модель для книг. Каждая книга связана с автором через
ForeignKey.
Шаг 2: Создание FormSet
Django предоставляет специальный класс inlineformset_factory для автоматического создания inline-форм. Этот класс связывает одну модель с другой через внешний ключ.
Рассмотрим, как создать inline-форму для управления книгами через форму автора:
from django.forms import modelformset_factory, inlineformset_factory
from django import forms
from .models import Author, Book
# Основная форма для модели Author
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = ['name', 'email']
# Inline-formset для модели Book
BookFormSet = inlineformset_factory(
Author, # Родительская модель
Book, # Модель, которая будет редактироваться через inline-формы
fields=['title', 'publish_date'], # Поля, доступные для изменения
extra=1, # Количество дополнительных пустых форм
can_delete=True # Возможность удалять связанные объекты
)
Обратите внимание на параметры inlineformset_factory:
- Первый аргумент — родительская модель (в данном случае,
Author). - Второй аргумент — модель, которая связана с родительской через
ForeignKey(в данном случае,Book). fields— список полей, которые мы хотим редактировать.extra— количество дополнительных, пустых форм в наборе.can_delete— еслиTrue, позволяет удалять существующие объекты.
Шаг 3: Создание представлений (views)
Теперь создадим представление для обработки формы автора и книг. Мы будем использовать AuthorForm и наш BookFormSet.
from django.shortcuts import render, redirect
from .models import Author
from .forms import AuthorForm, BookFormSet
def author_create_view(request):
# Создаем экземпляры форм
if request.method == 'POST':
author_form = AuthorForm(request.POST)
book_formset = BookFormSet(request.POST)
if author_form.is_valid() and book_formset.is_valid():
# Сохраняем автора
author = author_form.save()
# Привязываем книги к автору и сохраняем их
books = book_formset.save(commit=False) # Получаем объекты книг, но пока не сохраняем в базе
for book in books:
book.author = author
book.save()
return redirect('author_list') # Перенаправление после успешного сохранения
else:
author_form = AuthorForm()
book_formset = BookFormSet()
return render(request, 'author_form.html', {
'author_form': author_form,
'book_formset': book_formset,
})
Здесь:
- Мы обрабатываем как основной
AuthorForm, так иBookFormSetодновременно. - После проверки валидности обеих форм сохраняем объект автора, а затем связываем книги с этим автором перед их сохранением.
Шаг 4: Шаблон для отображения inline-форм
Создадим шаблон author_form.html для отображения формы автора и формы книг.
<form method="post">
{% csrf_token %}
<h2>Автор</h2>
{{ author_form.as_p }}
<h2>Книги</h2>
{{ book_formset.management_form }}
{% for form in book_formset %}
{{ form.as_p }}
{% endfor %}
<button type="submit">Сохранить</button>
</form>
Обратите внимание на использование {{ book_formset.management_form }}. Это обязательный элемент при работе с формсетами, так как он содержит метаданные о количествах форм, их статусах и идентификаторах.
Шаг 5: Улучшение работы с пустыми формами
По умолчанию Django добавляет только пустые формы, указанные в параметре extra. Вы можете настроить их отображение, чтобы пользователи могли добавлять больше форм.
Пример добавления пустой формы для книг динамически с помощью JavaScript:
<script>
const formsetContainer = document.querySelector('#form-container');
const addFormButton = document.querySelector('#add-form-btn');
addFormButton.addEventListener('click', function () {
const totalForms = document.querySelector('#id_book_set-TOTAL_FORMS');
const formIndex = totalForms.value; // Получаем индекс следующей формы
const newForm = document.querySelector('.empty-form').cloneNode(true);
newForm.innerHTML = newForm.innerHTML.replace(/__prefix__/g, formIndex);
formsetContainer.appendChild(newForm);
totalForms.value = parseInt(totalForms.value) + 1;
});
</script>
Типичные ошибки при работе с inline-формами
- Забыли включить
management_formв шаблон: если вы не добавите{{ book_formset.management_form }}, Django не сможет обработать формы корректно. - Недопустимые данные в одной из форм: если хотя бы одна форма в формсете невалидна, весь процесс сохранения провалится. Не забывайте использовать метод
is_valid()для проверки данных. - Не связали объекты с родительской моделью: после сохранения родительской формы нужно явно указать связь
book.author = author, иначе данные не будут корректно привязаны.
Реальное применение
Inline-формы широко используются в административных панелях, в e-commerce системах (например, добавление товаров в заказ), в блогах (создание постов с комментариями) и в CRM системах (работа с клиентами и их заказами). Они упрощают взаимодействие с пользователем и устраняют необходимость в создании множества отдельных форм.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ