Lila25milaJan. 25, 2019, 3:28 a.m.

Как использовать вложенные формы в 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 (Управление взаимоотношениями с клиентами) можно по этой ссылке .

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Comments

Only authorized users can post comments.
Please, Log in or Sign up
Timeweb

Let me recommend you the excellent hosting on which EVILEG is located.

For many years, Timeweb has been proving his stability.

For projects on Django I recommend VDS hosting

View Hosting
VS

C++ - Тест 003. Условия и циклы

  • Result:14points,
  • Rating points-10
VS

C++ - Тест 003. Условия и циклы

  • Result:14points,
  • Rating points-10
IP

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:10points,
  • Rating points-10
Last comments
A
  • Andrey
  • April 28, 2021, 1:25 a.m.

Django - Tutorial 036. How to add authentication through social networks. VKontakte

после того как дам разрешение для просмотра моего емайл, вот такая ошибка: AuthForbidden at /social-auth/complete/vk-oauth2/ Your credentials aren't allowed Вот сетингс: SOC…
DV

Qt/C++ - Lesson 051. QMediaPlayer – simple audio player

Добрый вечер. Хотел бы получить консультацию по работе с проектом на Mac OS. Открыл проект в QT и собрал его. Проблема в том, что он не воспроизводит треки и их названия зацикленно мелькают в по…
SS

Как соответствовать новым требованиям Google Play

Добрый день. Спасибо вам огромное за вашу статью! только начинаю изучать QT под Андроид 4 дня потратил на то чтобы подобрать версию QT которая наконец то скомпилирует мне на windo…
YA

PyQt5 - Tutorial 009. Using QThread with MoveToThread

Hello. Let's say I want to send some variables to "run" define. How can we do that? I modified your code, I tried something like below, but the GUI is frozen that way. I could not be able to und…
R

Распознавание изображений на Python с помощью TensorFlow и Keras

почему то вместо 50000 обрабатывает по 782 картинки кажду. эпоху
Now discuss on the forum

Потеря данных в сигнал/слот

вопрос решен
M

Qt/QML/Android(navigation button) - Стандартные клавиши навигации Андроид

Здравствуйте, пытаюсь заставить работать стандартную андроид-клавишу "назад", пытался разными способоами, они приведены в закомментированном коде. В том числе использовал https://evileg.com/ru/f…
M

Как включить OpenGL в Adnroid эмуляторе QtCreator

Здравствуйте, у меня работают виртуальные машины с Android, но только в дефолтной был включен OpenGL. Потом я удалил дефолтную, создал новые, а в них OpenGL отключен. Справа на втором скриншоте …

QScrollArea dynamically add QCheckBoxes

Всё правильно. Это просто спамер, который отправился в вечный бан.

qml зажатая кнопка мыши в одной MouseArea и сигналы мыши из другой MouseArea

добрый, вы не пробовали отслеживать область видимости мышки через: _mouseArea.containsMouse и когда мышка будет в другой зоне видимости обрабатывать ее состояния?
About
Services
© EVILEG 2015-2021
Recommend hosting TIMEWEB