Как я могу использовать формы/модели django для представления выбора между полями?

Как я могу использовать логические значения в поле модели для включения/отключения других полей. Если логическое значение истинно/ложно, я хочу, чтобы оно включало/отключало другие поля модели. Есть ли способ изначально выразить эти отношения с помощью моделей/форм/виджетов django? Я продолжаю писать собственные шаблоны для моделирования этих отношений, но не могу найти хороший способ представить их в django без специального шаблона.

Например:

class PointInTime(models.Model):
    is_absolute_time = models.BooleanField()
    absolute_time = models.DateTimeField()
    is_relative_time = models.BooleanField()
    days_before = models.IntegerField()

Поэтому, если is_absolute_time имеет значение True, я хочу, чтобы запись absolute_time была доступна для редактирования в графическом интерфейсе, а запись days_before была недоступна для редактирования и недоступна для редактирования. Если флаг «is_relative_time» имеет значение «Истина», я хочу, чтобы запись absolute_time была выделена серым цветом, а значение days_before было редактируемым. Таким образом, is_absolute_time и is_relative_time будут переключателями в одной и той же группе в графическом интерфейсе, и их два соответствующих поля будут доступны для редактирования только при выборе их переключателя. Это легко сделать в индивидуальном шаблоне, но есть ли способ использовать модель/форму в django, чтобы изначально показать эту связь?


person MikeN    schedule 03.02.2009    source источник


Ответы (2)


Было бы полезно прояснить, что вы подразумеваете под «изначально показать эту связь», и четко подумать о разделении задач.

Если все, что вам нужно, это «затенить» или отключить определенное поле на основе значения другого поля, это чисто проблема презентации/интерфейса, поэтому шаблон (и/или Javascript) является подходящим местом для его обработки.

Если вы хотите проверить, что отправленные данные внутренне непротиворечивы (т. е. absolute_time заполняется, если is_absolute_time имеет значение True и т. д.), это проблема проверки формы. Место для этой логики находится в методе clean() вашего объекта Form или ModelForm.

Если вы хотите гарантировать, что никакая модель PointInTime не может быть сохранена в базе данных без внутренней согласованности, это проблема уровня данных. Место для этого находится в пользовательском методе save() вашего объекта модели (Django 1.2 будет включать более обширная система проверки модели).

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

class PointInTime(models.Model):
    field_dependencies = {'is_absolute_time': 'absolute_time',
                          'is_relative_time': 'days_before'}
    ... fields here ...

Затем код вашей модели save() (или ваш код Form clean() или ваш шаблон) может использовать этот словарь, чтобы определить, какие поля должны быть включены/отключены в зависимости от значения другого. Однако это обобщение вряд ли стоит затраченных усилий, если только вы не предполагаете, что вам придется делать то же самое в ряде различных моделей.

Наконец, несколько альтернатив дизайна схемы, которые вы, возможно, захотите рассмотреть, чтобы лучше нормализовать свой уровень данных:

  • Если есть только два допустимых состояния (абсолютное и относительное), используйте одно логическое поле вместо двух. Затем вы избегаете возможных несоответствий (что значит, если оба логических значения имеют значение False? Или True?)

  • Или еще больше упростите, полностью исключив логические значения и просто используя значения Null в одном или другом из absolute_time/days_before.

  • Если допустимых состояний может быть более двух, используйте один IntegerField или CharField с вариантами выбора вместо двух логических полей. Та же причина, что и выше, но может быть более двух вариантов.

  • Поскольку RelativeTime и AbsoluteTime не имеют общих полей данных друг с другом, рассмотрите возможность их полного разделения на отдельные модели. Если у вас есть другие модели, которым нужен ForeignKey для одного или другого, вы можете смоделировать это с наследованием (как RelativeTime, так и AbsoluteTime наследуются от PointInTime, другие модели имеют ForeignKeys для PointInTime).

person Carl Meyer    schedule 03.02.2009

Я не совсем уверен, что вы делаете с этими объектами, но что бы ни выбрал пользователь, вы указываете на один момент времени. «5 дней назад» — это «четверг» и наоборот.

Таким образом, если даты не совпадают с сайтом (например, запись «5 дней назад» по-прежнему будет означать четверг, завтра и т. д.), наверняка это проблема только интерфейса? Если это так, я бы придерживался одного значения даты в вашей модели и позволил форме и представлению выполнять всю работу.

Это решает автоматически сгенерированную административную сторону вещей, поскольку у вас будет только одно поле, с которым нужно бороться, но оно изначально не даст вам выбора между двумя, если вы не напишете свой собственный виджет формы и не переопределите класс ModelAdmin для вашей модели.

Если это не так, пожалуйста, игнорируйте этот ответ.

person Oli    schedule 03.02.2009
comment
Относительное время будет вращаться относительно какого-либо другого значения даты и времени (либо сегодня, либо в какой-либо другой записи). Таким образом, в базе данных оно моделируется по-разному, я бы фактически сохранил 5 как целое число, чтобы представить относительное время даты и времени за 5 дней до какой-либо другой дата и время. - person MikeN; 03.02.2009