Как установить начальное значение для полей отношений в админке Django? - PullRequest
0 голосов
/ 21 февраля 2019

Сводка

Мы бы хотели установить начальный выбор полей выбора, представляющих различные виды отношений модели, на базовой странице «добавить» или «изменить» в админке Django.Первоначальный выбор должен быть сохранен в базе данных, если пользователь нажимает одну из кнопок «Сохранить».

Мы специально хотим сделать это, установив значение initial в полях формы (для ModelAdminили TabularInline).

Вопрос в следующем:

Какое «значение» присваивать Field.initial, для различных видов отношенийполя формы?

Фон

Предположим, у нас есть простое Model с одним или несколькими полями отношений , т.е. OneToOneField, ForeignKey или ManyToManyField.По умолчанию последняя имеет модель неявная through, но может также использовать модель явная through, как объяснено в документах .Явная модель through - это модель с как минимум двумя ForeignKey полями.

Поля отношений, представленные полями выбора, автоматически появляются в стандартном ModelAdmin "add"или" изменить "формы, за исключением ManyToManyField с явной through моделью.Для этого требуется встроенный символ, такой как TabularInline, как объяснено здесь в документах.

Обратите внимание, что неявное ManyToManyField связано с ModelMultipleChoiceField в форме (admin), а другие поля отношений связаны с ModelChoiceField.Последний включает ManyToManyField с явной through моделью, потому что это фактически представлено полем ForeignKey в TabularInline.

Цель

Теперь рассмотрим базовую страницу Django ModelAdmin «add» (или «change») для этой модели, включая строчные для любых явных through моделей.,Пример на основе пиццерии Джанго приведен ниже.

Мы хотим достичь двух целей:

  1. установить начальный выбор для одного или несколькихполя отношений
  2. начальный выбор должен быть сохранен в базе данных, если мы нажмем одну из кнопок «Сохранить» (при условии, что мы не изменили выбор вручную)

Обратите внимание, что второй кажется тривиальным, но, по-видимому, нет (см. Ниже).

django pizza admin example

Подход

Насколько далеконасколько я знаю, есть несколько способов достичь этого:

  • установить в поле модели значение default, например, ForeignKey.default, опционально передавая вызываемую ( docs )
  • установить значение Form.initial для формы администратора ( документы )
  • установить значение Field.initial для поля формы администратора ( документы )

Независимо от того, какой подход «лучший» для определенного варианта использования, этот вопрос относится к последнему подходу: setting значение Field.initial.

Мы делаем это путем расширения ModelAdmin.formfield_for_dbfield (или TabularInline.formfield_for_dbfield) следующим образом:

def formfield_for_dbfield(self, db_field, request, **kwargs):
    if db_field.name == 'some_relationship_field_name':
        kwargs['initial'] = value
    return super().formfield_for_dbfield(db_field, request, **kwargs)

value в этом примере может бытьobj.id, obj, [obj.id, ...] или [obj, ...], где obj - это Model экземпляр.

Задача

В зависимости от типа поля отношения,различные типы value могут работать или не работать.

Для ManyToManyField с неявной through моделью мы можем только назначить список объектов, так что один будет простым.

Для других отношений в некоторых случаях начальный выбор поля выбора соответствует назначенному значению, но не сохраняется (например, потому что Field.has_changed возвращает False).В других случаях исходное значение поля выбора сохраняется, но не соответствует назначенному значению.

Вопрос

Итак, очевидный вопрос:

Как правильно value назначить Field.initial для различных типов полей отношений наадминистративная форма?

Похожие

Несмотря на то, что я потратил довольно много времени на поиск, я не смог найти четкого ответа ни в документации, ни в SO, ни где-либо еще.Также пытался выяснить это через исходный код, но это оказалось довольно сложно.

Некоторые похожие вопросы:

1 Ответ

0 голосов
/ 21 февраля 2019

В таблице ниже приведены результаты некоторых экспериментов с выделенным минимальным примером с использованием Django 2.1.Исходя из таблицы, представляется, что:

  • obj или obj.id работает только для OneToOneField, а ForeignKey
  • [obj.id] работает для всех отношений, представленныхModelChoiceField
  • [obj] работает только для неявного ManyToManyField, который представлен ModelMultipleChoiceField

Однако я не могу сказать, что такое Намеченный способ сделать это для каждого случая.Например, бессмысленно назначать список для поля ForeignKey.Однако забавно то, что, хотя ManyToManyField с явной through моделью имеет встроенный ModelChoiceField для ForeignKey, мы не можем просто присвоить obj или obj.id: это должно бытьв списке.

Здесь приветствуются любые комментарии.

Ключ для таблицы 1:

  • 1 : начальный выбор поля выборасоответствует значению Field.initial
  • 2 : первоначальное выделение поля выбора сохраняется после нажатия кнопки «Сохранить» (ПРИМЕЧАНИЕ: если 1 не выполнено, то начальное выделение поля выборапервая доступная опция)
  • T : TypeError (объект не повторяется)
  • A : AttributeError (объект int имеетнет атрибута 'pk')

Обратите внимание, что наше желаемое поведение равно 1 & 2 .

Таблица 1: результат назначения различныхзначения до Field.initial для различных полей отношений

|                                                       |  value assigned to Field.initial  |
|-----------------|----------|--------------------------|-------|--------|-------|----------|
| model field     | through  | associated form field    | obj   | obj.id | [obj] | [obj.id] |
|-----------------|----------|--------------------------|-------|--------|-------|----------|
| OneToOneField   | n/a      | ModelChoiceField         | 1 & 2 | 1 & 2  | 2     | 1 & 2    |
| ForeignKey      | n/a      | ModelChoiceField         | 1 & 2 | 1 & 2  | 2     | 1 & 2    |
| ManyToManyField | explicit | ModelChoiceField         | 1     | 1      | 2     | 1 & 2    |
| ManyToManyField | implicit | ModelMultipleChoiceField | T     | T      | 1 & 2 | A        |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...