Lila25mila
Lila25mila25 января 2019 г. 3:28

Как использовать вложенные формы в Django

Django Formsets управляет сложными повторяющимися полями форм в представлении. Используя формуляры, вы можете узнать, сколько форм было изначально, какие были изменены, а какие должны быть удалены.
Подобно формам и моделям форм, Django предлагает наборы моделей форм, которые упрощают задачу создания набора форм для формы, обрабатывающей несколько экземпляров модели.


Django также предоставляет встроенные наборы форм, которые можно использовать для обработки набора объектов, принадлежащих общему внешнему ключу.
В приведенных ниже примерах моделей мы можем написать inline-formset для обработки всех дочерних элементов, для родителя или всех адресов дочерних элементов.

# models.py

class Parent(models.Model):
    name = models.CharField(max_length=255)

class Child(models.Model):
    parent = models.ForeignKey(Parent)
    name = models.CharField(max_length=255)

class Address(models.Model):
    child = models.ForeignKey(Child)
    country = models.CharField(max_length=255)
    state = models.CharField(max_length=255)
    address = models.CharField(max_length=255)
# forms.py

from django.forms.models import inlineformset_factory

ChildrenFormset = inlineformset_factory(models.Parent, models.Child, extra=1)
AddressFormset = inlineformset_factory(models.Child, models.Address, extra=1)

Используя описанные выше наборы форм, вы можете обрабатывать все дочерние элементы для родителя на одной странице и обрабатывать все адреса дочерних элементов на другой странице. Если же вы хотите разрешить пользователям добавлять или редактировать все дочерние элементы вместе с адресами на одной странице, то у вас должен быть полный набор форм адресов для каждой дочерней формы в дочернем наборе форм.
В этом случае появляется смысл использовать вложенные формы. Вложенный formset - это обычный inline-formset.
Для обработки вложенных форм необходимо сделать следующие шаги:

Шаг 1: Создание базового inline-formset

# forms.py

from django.forms.models import BaseInlineFormSet

class BaseChildrenFormset(BaseInlineFormSet):
    pass

ChildrenFormset = inlineformset_factory(models.Parent,
                                        models.Child,
                                        formset=BaseChildrenFormset,
                                        extra=1)

Шаг 2. Прикрепление вложенного набор форм для каждой формы, как показано ниже. Супер-класс BaseInlineFormSet определяет метод add_fields, который отвечает за добавление полей для каждой формы в наборе форм. Также, здесь мы можем написать логику, чтобы связать вложенный набор форм.

# forms.py
class BaseChildrenFormset(BaseInlineFormSet):

    def add_fields(self, form, index):
        super(BaseChildrenFormset, self).add_fields(form, index)

        # save the formset in the 'nested' property
        form.nested = AddressFormset(
                        instance=form.instance,
                        data=form.data if form.is_bound else None,
                        files=form.files if form.is_bound else None,
                        prefix='address-%s-%s' % (
                            form.prefix,
                            AddressFormset.get_default_prefix()),
                        extra=1)

Примечание: Здесь мы создали новое свойство с именем "form.nested", которое содержит вложенный набор форм (AddressFormset).

Шаг 3. Обработка набора форм и вложенных наборов форм в представлениях

# views.py

def manage_children(request, parent_id):
    """Edit children and their addresses for a single parent."""

    parent = get_object_or_404(models.Parent, id=parent_id)

    if request.method == 'POST':
        formset = forms.ChildrenFormset(request.POST, instance=parent)
        if formset.is_valid():
            formset.save()
            return redirect('parent_view', parent_id=parent.id)
    else:
        formset = forms.ChildrenFormset(instance=parent)

    return render(request, 'manage_children.html', {
                  'parent':parent,
                  'children_formset':formset})

Шаг 4: Визуализация вложенного набора форм в шаблоне

# manage_children.html (Just formset display part)

{{ children_formset.management_form }}
{{ children_formset.non_form_errors }}

{% for child_form in children_formset.forms %}
    {{ child_form }}

    {% if child_form.nested %}
        {{ child_form.nested.management_form }}
        {{ child_form.nested.non_form_errors }}

        {% for nested_form in child_form.nested.forms %}
            {{ nested_form }}
        {% endfor %}

    {% endif %}

{% endfor %}

Есть несколько моментов, на которые нужно обратить внимание:

1. Проверка. При проверке формы в наборе форм нам также необходимо проверить ее подформы, которые находятся во вложенном наборе форм.

2. Сохранение данных. При сохранении формы также необходимо сохранять дополнения и изменения к формам во вложенном наборе форм.

Когда страница отправлена, мы вызываем formset.is_valid () для проверки форм. Мы переопределяем is_valid в нашем наборе форм, чтобы добавить проверку и для вложенных наборов форм.

# forms.py

class BaseChildrenFormset(BaseInlineFormSet):
    ...

    def is_valid(self):
        result = super(BaseChildrenFormset, self).is_valid()

        if self.is_bound:
            for form in self.forms:
                if hasattr(form, 'nested'):
                    result = result and form.nested.is_valid()

        return result

На этом проверка форм и вложенных форм завершается. Теперь нам нужно обработать сохраненное. Для этого необходимо переопределить метод save для сохранения родительского набора форм и всех вложенных наборов форм.

# forms.py

class BaseChildrenFormset(BaseInlineFormSet):
    ...

    def save(self, commit=True):

        result = super(BaseChildrenFormset, self).save(commit=commit)

        for form in self.forms:
            if hasattr(form, 'nested'):
                if not self._should_delete_form(form):
                    form.nested.save(commit=commit)

        return result

Метод save отвечает за сохранение форм в наборе форм, а также всех форм во вложенном наборе форм для каждой формы.
Узнать больше о пакете с открытым исходным кодом Django CRM (Управление взаимоотношениями с клиентами) можно по этой ссылке .

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

КГ
  • 22 июня 2022 г. 5:02
  • (ред.)

Спасибо за полезную статью. Подскажите пожалуйста, что делать если нужно реализовать большее количество вложенных форм?
Например если на модель Address ссылается fk другой модели, на которую в свою очередь ссылается еще одна модель.
И нужно создавать все объекты с одной страницы.

Evgenii Legotckoi
  • 24 августа 2022 г. 7:39

В этом примере и так два уровня вложенности, всё остальное делается подобным способом.

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50баллов,
  • Очки рейтинга-4
m
  • molni99
  • 26 октября 2024 г. 11:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
m
  • molni99
  • 26 октября 2024 г. 11:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20баллов,
  • Очки рейтинга-10
Последние комментарии
i
innorwall16 ноября 2024 г. 18:33
Qt/C++ - Урок 018. QGraphicsItem - наследование и СЛОТы where to buy priligy in usa Now let us do something for you
i
innorwall16 ноября 2024 г. 17:52
Qt/C++ - Урок 063. Добавление окон внутри главного окна приложения с помощью QMdiArea Another thing that might help is Milk Thistle or dandelion root which help cleanse your liver as the liver plays a big part in getting that Estrogen out of your body priligy reddit
i
innorwall16 ноября 2024 г. 14:55
Qt/C++ - Урок 036. QWebView - пишем простейший браузер на Qt Figure 7 The network of ОІ estradiol where to buy priligy usa
i
innorwall16 ноября 2024 г. 14:38
Анонсирование Qt для MCU donde comprar priligy mexico If you have suppressed vitamin d this could be contributing to your Low T levels and all the bad things associated with that
i
innorwall16 ноября 2024 г. 14:05
Qt/C++ - Урок 015. QTableWidget или Как сделать таблицу с чекбоксами 5 mg weight gain We thought price negotiation was a huge source of friction dapoxetine for premature
Сейчас обсуждают на форуме
i
innorwall16 ноября 2024 г. 13:20
добавить qlineseries в функции Bone densitometry is the most accurate clinical predictor of osteoporosis priligy medicine
t
tonypeachey115 ноября 2024 г. 17:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
i
innorwall11 ноября 2024 г. 21:55
Всё ещё разбираюсь с кешем. priligy walgreens levitra dulcolax carbs The third ring was found to be made up of ultra relativistic electrons, which are also present in both the outer and inner rings
9
9Anonim25 октября 2024 г. 19:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Следите за нами в социальных сетях