Вложенные формсеты в Django

Задача стояла следующая:
сделать карточку создания-редактирования тренировки, которое состоит из упражнений, каждое из которых состоит из подходов. При этом должна быть возможность создавать тренировку по шаблону, при этом должны выводиться формы упражнений с предзаполненными данными, а также пустые определённого количества форм для ввода подходов (количество задаётся в шаблоне). Также должна сохраниться валидация всех форм, невозможность сохранения тренировок без упражнений и упражнений без подходов.

Вот примерно что получилось

Для этого понадобилась одна ModelForm и два основательно переопределёных InlineFormSet.
Остановлюсь на некоторых особенностях формсетов:

  • Методы, отвечающие за выяснение того, по данным каких форм нужно создавать новые модели подходов, а какие нужны для изменения информации о старых. По умолчанию эти методы основываются на количестве форм self.initial_form_count(), а мне нужно было уметь перемещать эти формы, поэтому решил основываться на том, есть ли у формы заполненный первичный ключ.
  • Сохранение существующей модели переделано, т.к. в противном случае будет создаваться новая модель (не будет найден первичный ключ)
  • Добавление полей в форму упражнения добавляет ещё и определённое в шаблоне тренировки количество пустых форм для добавления данных по подходам упражнения, разное для разных упражнений. Для этого при создании формсета задаётся self._nested_extras — словарь с ключом — номером формы и значением — количеством форм для ввода подходов.
    Если на странице пользователь добавлет упражнение, то посылается POST-запрос, поэтому self.data будет заполнено, а данных по вложенному формсету подходов для создаваемого упражнения в это свойстве нет, от чего у Django возникает когнитивный диссонанс, поэтому при создании формсета задаётся self._nested_allow_using_data — словарь с ключами-номерами форм и булевым значением, искать ли данные для вложенного формсета подходов в POST-е при валидации форм.
    Используются эти параметры так:
  • Сохранение формсета упражнений: переопределённый метод save_all сначала сохраняет формы без коммита, чтобы переопределённый метод save_new для каждой вложенной формы подхода заполнил внешний ключ — ссылку на модель упражнения. После этого сохраняются все формы и вложенные формы.

Вот полный код:
views.py

Соответствующий шаблон:

Использованы статьи:
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets ;)
http://yergler.net/blog/2009/09/27/nested-formsets-with-django/
http://stackoverflow.com/questions/877723/inline-form-validation-in-django/1884760
http://stackoverflow.com/questions/1206903/how-do-i-require-an-inline-in-the-django-admin
http://stackoverflow.com/questions/442040/pre-populate-an-inline-formset

2 Responses so far.

  1. откуда берется Training() ?

LEAVE A COMMENT