Щоб зрозуміти, навіщо нам потрібні 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 }}. Це обов'язковий елемент при роботі з formset, оскільки він містить метадані про кількість форм, їх статуси та ідентифікатори.
Крок 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 системах (робота з клієнтами та їх замовленнями). Вони спрощують взаємодію з користувачем і усувають необхідність у створенні багатьох окремих форм.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ