Добавить поля в Django ModelForm, которые не входят в модель
У меня есть модель, которая выглядит так:
class MySchedule(models.Model):
start_datetime=models.DateTimeField()
name=models.CharField('Name',max_length=75)
С его помощью появляется ModelForm:
class MyScheduleForm(forms.ModelForm):
startdate=forms.DateField()
starthour=forms.ChoiceField(choices=((6,"6am"),(7,"7am"),(8,"8am"),(9,"9am"),(10,"10am"),(11,"11am"),
(12,"noon"),(13,"1pm"),(14,"2pm"),(15,"3pm"),(16,"4pm"),(17,"5pm"),
(18,"6pm"
startminute=forms.ChoiceField(choices=((0,":00"),(15,":15"),(30,":30"),(45,":45")))),(19,"7pm"),(20,"8pm"),(21,"9pm"),(22,"10pm"),(23,"11pm")))
class Meta:
model=MySchedule
def clean(self):
starttime=time(int(self.cleaned_data.get('starthour')),int(self.cleaned_data.get('startminute')))
return self.cleaned_data
try:
self.instance.start_datetime=datetime.combine(self.cleaned_data.get("startdate"),starttime)
except TypeError:
raise forms.ValidationError("There a problem with your start or end date")
В принципе, я пытаюсь сломать поле DateTime в модели на 3 более удобных для использования поля формы - выбор даты, выпадающее меню и минутное раскрывающееся меню. Затем, как только я получил три входа, я снова их собираю в DateTime и сохраняю в модели.
Несколько вопросов:
1) Не совсем ли это так? Я не хочу создавать поля в модели в течение нескольких часов, минут и т.д., Так как все это в основном только промежуточные данные, поэтому я хотел бы разбить поле DateTime на подполя.
2) Трудность, с которой я сталкиваюсь, заключается в том, что поле startdate пустое - кажется, что он никогда не проверяется на отсутствие пробелов и просто заканчивается тем, что он запускает TypeError позже, когда программа ожидает дату и получает Никто. Где Django проверяет пустые входы и поднимает ошибку, которая в конечном итоге возвращается к форме? Это моя ответственность? Если да, то как это сделать, поскольку он не оценивает clean_startdate(), поскольку startdate не находится в модели.
3) Есть ли лучший способ сделать это с наследованием? Возможно, наследуйте MyScheduleForm в BetterScheduleForm и добавьте туда поля? Как мне это сделать? (Я играю с ним более часа и, похоже, не могу получить его)
Спасибо!
[Edit:] Отключен возврат self.cleaned_data - потерял его в оригинале copy/paste
Ответы
Ответ 1
-
Если бы я был вами, я бы использовал настраиваемые виджеты даты/времени Django-admin для ввода записей даты/времени.
-
Что касается проверки формы, убедитесь, что вы передали форму, связанную с запросом, чтобы она отображала ошибки на основе форм. (Пример кода ниже)
-
Что касается использования наследования, это будет излишним для этого случая использования, поскольку оно не будет служить какой-либо цели, и было бы лучше, если бы все было просто.
Пример кода:
if request.POST:
form = MyScheduleForm(request.POST)
if form.is_valid():
# Specific stuff with the variables here
pass
else:
form = MyScheduleForm()
Ответ 2
Хорошо, я думаю, что понял:
Как и в Django 1.2, running is_valid() запускает проверку модели на ModelForms. Я предположил, что поля будут проверяться на пустые значения перед ударом функции clean(), поэтому моя чистая функция не проверяет пустые значения или типы None. В принципе, мой clean() в моей модели выглядит примерно так:
def clean(self):
if self.start_datetime > datetime.now():
raise ValidationError('Start date can\'t be in the future')
Поэтому я полагаю, что в основном отвечаю на мой вопрос. Однако у меня остается 1 вопрос:
Лучше ли проверять пустые значения в модели clean(), или есть лучший способ сделать это? Кажется, что взломанный для проверки пробелов в модели, а не в ModelForm, - это проверка на поле формы, которое должно помечать отсутствующие входы в обязательных полях?
Спасибо за помощь всем.
Ответ 3
1: Я не думаю, что это неправильно, потому что у вас есть очень специфический материал:
- Конкретные записи времени (полдень, заканчивающиеся на 5 вечера).
- 15-минутные приращения для startminutes
2: Обновление: комментарий ниже говорит, что ваше поле должно быть required=True
по умолчанию. Это правда, вы должны получать ValidationError
с вашей формой, если поле остается пустым.
Можете ли вы опубликовать TypeError
, о котором вы говорите? Это происходит за пределами блока clean()
? Поскольку, если вы не возвращаете cleaned_data
из своей чистой функции, как в вашем примере, ваша форма не будет содержать никаких данных, даже если она изначально проверяет, не поднимая никаких ValidationErrors
.
В любом случае вы можете изучить методы clean_
для каждой проверки поля.
def clean_startdate(self):
if not self.cleaned_data['startdate']:
raise forms.ValidationError("Must enter a start date")
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-clean-method
3: Можете ли вы пояснить, что вы пытаетесь сделать с наследованием? Похоже, что ваши определения полей очень специфичны для этой формы, поэтому она принадлежит прямо здесь, в MyScheduleForm
. Наследование предназначено для повторного использования кода:)
Если вы хотите повторно использовать это для нескольких DateTimeField
s, да, вы можете использовать наследование формы. Вы можете определить ModelForm
, как сейчас, подклассировать его и переопределить родительский Meta
, как показано здесь в документах, чтобы использовать его на нескольких моделях:
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#form-inheritance
Я также проверил, как django делает свой SplitDateTimeWidget (проверьте источник):
http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.SplitDateTimeWidget
Есть также некоторые другие "сторонние" таймеры с датой подсчета, которые стоит посмотреть и на interwebs!
Ответ 4
Для полей формы, которые могут содержать пустые значения, вы должны объявить это поле следующим образом:
start_datetime=models.DateTimeField(blank=True, null=True)
Это сообщает форме, что это может быть blank
, и что поле базы данных может быть null
. Это может решить эту проблему.
Почему вы используете ModelForm, если вы пытаетесь включить поля, которые не являются частью модели? ModelForms предназначены для быстрого создания форм, которые напрямую привязаны к вашей модели. Конечно, у них есть различные настройки, но изменение фактических полей мне кажется чем-то, для чего нужна обычная форма.
В противном случае, если вы просто хотите разделить VIEW формы, а не форму, создайте собственный виджет, чтобы отобразить поле DateTime, например SplitDateTimeWidget. Подклассируйте его и предоставьте свои CHOICES для значений выпадающего списка.