Django ModelForm з багатьма полями

Вбудований ORM Django має поле ManyToMany, яке ви можете вибрати. Я думаю, що типовий мультиселектор відстійний, і це підтвердили багато кінцевих користувачів, описуючи, як селектор змушує їх помилятися під час редагування цих конкретних полів. Тут я опишу дві речі. По-перше, як змінити віджет цього поля на щось більш смачне. Далі я опишу деякі зависання, на які слід бути обережним, щоб стежити, коли ви використовуєте це поле з ModelForms, особливо під час збереження.

джошуа

Відношень багато-до-багатьох краще уникати, якщо це можливо. Вони брудні і змушують весь ваш код обробляти кілька екземплярів відношення. Список інгредієнтів в їжі може бути представлений у взаємозв'язку "багато до одного", якщо ви не хочете повторно використовувати ці інгредієнти. Тоді у вас є два варіанти; або дозволити копіювання, або використовувати поле "багато-до-багатьох". Оскільки ці інгредієнти можуть бути змінені, і це потрібно розподіляти до всіх страв, до складу яких вони входять, я обрав останнє рішення.

Моделі та код форми

Ось основний код моделі їжі, який також доступний як суть models.py.

Все це базове моделювання. Інгредієнти мають назву та стосунки до дієти та харчових уподобань. Харчування може містити багато інгредієнтів, назву та набір категорій меню. 1

Тепер давайте поглянемо на форму додавання/редагування інгредієнта. Це багатофункціональний ModelForm, також доступний як зміст forms.py.

Усі вигадливі речі відбуваються в __init__. Я ініціалізую форму за допомогою IngredientForm (бренд = бренд), щоб налаштувати фільтрацію об’єктів FoodPreference, і змінити віджети на CheckBoxSelectMultiple. Це чудово відображається як рядок прапорців замість дурного мультивибору.

Фантастичні взаємозв'язки M2M з ModelForms

Дивина починається, коли ми намагаємось зберегти цю форму.

Це видає помилку, оскільки ця форма спеціально виключає відносини франшизи. Стандартне рішення ForeignKey полягає у використанні commit = False та визначенні самостійно.

Це працює без видимих ​​помилок, доки ви не повернетесь до цього об’єкта і не помітите, що жоден з відносин M2M (Дієти та FoodPreference) не був збережений. Чому так трапляється?

Інший побічний ефект використання commit = False спостерігається, коли ваша модель має відношення "багато до багатьох" з іншою моделлю. Якщо ваша модель має відношення багато-до-багатьох, і ви вказуєте commit = False при збереженні форми, Django не може негайно зберегти дані форми для відношення багато-до-багатьох. Це пов’язано з тим, що неможливо зберегти дані “багато-до-багатьох” для екземпляра, поки екземпляр не існує в базі даних.

Ось як він змінює код.

Зверніть увагу, що save_m2m викликається для старого об'єкта форми, не збережений об'єкт моделі.

Це повинно бути більш помітним, згаданим у документації Django. Лише поринувши в те, як працює commit = False, я знайшов цей фрагмент.

Загорнути

Моделі Django та ModelForms чудові, але, безумовно, обмежені в деяких аспектах. Після того, як ви освоїте основи, невеликі зміни (наприклад, такі) можуть зайняти деякий час, щоб зрозуміти. Хороші новини - це коли ви це робите, вони прості, і ви дізнаєтесь більше.

Почніть складати список власних полів Django, спадкових абстрактних моделей та деяких нових віджетів, щоб зробити передню сторону гарнішою. Це заощадить ваш час пізніше і змусить вас отримати цінний шаблон повторного використання.

Це буде замінено на ForeignKey, коли я отримаю можливість. ↩