JavaRush /Курси /Модуль 3: Django /Створення форм для пов'язаних моделей

Створення форм для пов'язаних моделей

Модуль 3: Django
Рівень 13 , Лекція 7
Відкрита

Уяви, що ти створюєш блог, де є пости і категорії. Кожен пост відноситься до однієї або кількох категорій (зв'язок ManyToMany). Блогеру потрібен інтерфейс, щоб не тільки додати новий пост, але й відредагувати категорії прямо в тій самій формі. Як це зробити? Використовуй форми для пов'язаних моделей!

У реальних проєктах такі форми використовуються всюди, де є необхідність працювати з даними з кількох таблиць/моделей бази даних. Це ж набагато зручніше для користувачів — один інтерфейс для всього.

Підготовка: створимо моделі та зв'яжемо їх

Перед тим як почати роботу з формами, спочатку налаштуємо моделі. У якості прикладу будемо працювати з блогом.

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    categories = models.ManyToManyField(Category, related_name='posts')

    def __str__(self):
        return self.title

Тут у нас дві моделі: Category для категорій та Post для постів. Пости можуть бути пов'язані з кількома категоріями через поле categories (зв'язок типу ManyToMany).

Підхід №1: Працюємо з окремими формами

Перший підхід до роботи зі зв'язаними моделями — це використання окремих форм для кожної моделі. Наприклад, форма для постів та форма для категорій. Почнемо з простого.

Форма для створення постів

from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'content', 'categories']

Форма для створення категорій

from django import forms
from .models import Category

class CategoryForm(forms.ModelForm):
    class Meta:
        model = Category
        fields = ['name']

Кожна модель тут має свою окрему форму. Поле categories автоматично відображається у формі PostForm як MultipleChoiceField, де користувач зможе обирати з існуючих категорій.

Кроки у представленнях

Тепер потрібно написати представлення, щоб обробити обидві форми. Роботу з категоріями та постами можна розділити.

from django.shortcuts import render, redirect
from .models import Post, Category
from .forms import PostForm, CategoryForm

def create_post(request):
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('post_list')  # Перенаправляємо на список постів
    else:
        form = PostForm()
    return render(request, 'blog/create_post.html', {'form': form})

def create_category(request):
    if request.method == 'POST':
        form = CategoryForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('category_list')  # Перенаправляємо на список категорій
    else:
        form = CategoryForm()
    return render(request, 'blog/create_category.html', {'form': form})

У шаблонах це виглядатиме приблизно так:

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Зберегти</button>
</form>

Цей підхід зручний, але вимагає, щоб користувач спочатку створив категорії, а потім додав пости і вибрав відповідні категорії. Хочете більше зручності? Давайте подивимося, як зробити одну форму, яка буде підтримувати все.

Підхід №2: Inline форми для пов'язаних моделей

Коли потрібно дати користувачу можливість редагувати одразу і пост, і пов'язані категорії, на допомогу приходять inline форми. Django надає потужний інструмент під назвою inlineformset_factory.

Створення Inline FormSet

from django.forms import inlineformset_factory
from .models import Post, Category

CategoryInlineFormSet = inlineformset_factory(
    Post,  # Батьківська модель
    Category,  # Пов'язана модель
    fields=('name',),  # Поля, які редагуються
    extra=1,  # Кількість порожніх форм для нових об'єктів
    can_delete=True  # Можливість видаляти пов'язані об'єкти
)

Тут inlineformset_factory створює форму, яка дозволяє редагувати категорії, пов'язані з конкретним постом.

Представлення для роботи з Inline FormSet

Тепер потрібно написати представлення, щоб відобразити і обробити нашу inline форму.

from django.shortcuts import render, get_object_or_404, redirect
from .models import Post
from .forms import PostForm
from .forms import CategoryInlineFormSet

def edit_post(request, pk):
    post = get_object_or_404(Post, pk=pk)
    form = PostForm(instance=post)
    formset = CategoryInlineFormSet(instance=post)

    if request.method == 'POST':
        form = PostForm(request.POST, instance=post)
        formset = CategoryInlineFormSet(request.POST, instance=post)
        if form.is_valid() and formset.is_valid():
            form.save()
            formset.save()
            return redirect('post_list')  # Перенаправляємо на список постів

    return render(request, 'blog/edit_post.html', {'form': form, 'formset': formset})

Шаблон з основною формою та inline формами

Тепер створимо шаблон, де обидві форми будуть відображатися разом.

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}

    <h3>Категорії:</h3>
    {{ formset.management_form }}
    {% for form in formset %}
        {{ form.as_p }}
    {% endfor %}

    <button type="submit">Зберегти</button>
</form>

Як це працює?

  1. PostForm дозволяє редагувати дані поста (title, content).
  2. CategoryInlineFormSet дозволяє редагувати категорії, пов'язані з постом.
  3. Якщо користувач додає категорію або видаляє існуючу, це автоматично фіксується в базі.

Підхід №3: Використання віджетів для ManyToMany

Якщо тобі потрібно просте рішення для зв'язку ManyToMany, можна використовувати вбудовані віджети Django. Наприклад, віджет CheckboxSelectMultiple дозволяє відображати пов'язані об'єкти у вигляді списку чекбоксів.

Твоя форма буде виглядати так:

from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'content', 'categories']
        widgets = {
            'categories': forms.CheckboxSelectMultiple()
        }

Тепер у шаблоні поле categories буде представлено списком чекбоксів, де користувач зможе вибрати декілька категорій.

Практичне завдання

  1. Реалізуй модель авторів Author, пов'язаних із постами через поле ForeignKey.
  2. Створи форму, яка дозволить редагувати пости та пов'язані з ними дані про авторів.
  3. Налаштуй представлення та шаблон для роботи з цією формою.

Такий підхід дасть тобі реальне розуміння, як працюють форми для пов'язаних моделей і які з них зручніше використовувати в різних сценаріях.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ