2011-01-12 2 views
11

У меня есть модель, которая выглядит как:Добавление полей в 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's a problem with your start or end date") 

В принципе, я пытаюсь разделите поле DateTime в модели на 3 более удобные для использования поля формы - выбор даты, выпадающее меню и минутное раскрывающееся меню. Затем, как только я получаю три входа, я их собираю в DateTime и сохраняю в модели.

Несколько вопросов:

1) Является ли это совершенно неправильный путь делать это? Я не хочу создавать поля в модели в течение нескольких часов, минут и т. Д., Так как все это всего лишь промежуточные данные, поэтому я хотел бы разбить поле DateTime на подполя.

2) Трудность, с которой я сталкиваюсь, - это когда пустое поле пуста - кажется, что он никогда не проверяется на отсутствие пробелов и просто заканчивается тем, что выпускаете TypeError позже, когда программа ожидает дату и получает Нет. Где Django проверяет пустые входы и поднимает ошибку, которая в конечном итоге возвращается к форме? Это моя ответственность? Если да, то как это сделать, поскольку он не оценивает clean_startdate(), поскольку startdate не находится в модели.

3) Есть ли лучший способ сделать это с наследованием? Возможно, наследуйте MyScheduleForm в BetterScheduleForm и добавьте туда поля? Как мне это сделать? (Я играл с ним более часа и, похоже, не мог его получить)

Спасибо!

[Edit:] Брошенный обратный self.cleaned_data - потерял в копировании/вставке первоначально

+0

В общем, ModelForm может содержать любые поля, которые вы хотите. В этом отношении это похоже на обычную форму. Единственная проблема заключается в том, что вам нужно будет реализовать начальные данные, соответствующие методы clean() и соответствующий метод save(), если эти поля не существуют в модели, поскольку ModelForm пытается автоматически генерировать эти вещи автоматически модель. – Cerin

ответ

0

1: Я не думаю, что это неправильно, потому что у вас есть некоторые очень конкретные вещи там происходят:

  • Конкретные записи времени (полдень, заканчивающийся в 5PM ..) с шагом
  • 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, да, вы можете использовать наследование формы. Вы можете определить ModelForm как у вас есть сейчас, подкласс и переопределить родителя Meta, как показано здесь, в документации, чтобы использовать его на нескольких моделях: http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#form-inheritance

Я бы также проверить, как Джанго делает его SplitDateTimeWidget (проверьте источник): http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.SplitDateTimeWidget

Есть также некоторые другие «сторонние» таймеры с расщепленной датой, которые стоит взглянуть и на interwebs!

+0

required = True - это значение по умолчанию для полей формы django. –

+0

Хорошо, но тогда у него не должно быть проблемы с №2. Интересно, почему это поле не проверяется? hmm –

+0

Спасибо за ваш ответ - вот несколько ответов на ваши вопросы: 1) Я знаю, что по умолчанию требуется = True. Проблема в том, что если немодельные поля (startdate, starthour и т. Д.) Остаются пустыми, он не генерирует исключение и возвращает информацию о «недостающем поле» в мою форму. Я хочу, чтобы он проверял наличие пустоты и перекрывал, если есть пустое поле, но кажется, что оно пропустило это до тех пор, пока пустое поле не вызовет проблемы позже в clean() 2) Я попробовал добавить функцию clean_startdate(), но кажется чтобы никогда не вызывались. Однако функции clean_ для полей в моей модели DO вызываются. – Cyclic

1
  1. Если бы я тебя, я бы использовал customised Django-admin date/time widget(s) для ввода записи даты/времени.

  2. Что касается проверки формы, обязательно передайте форму, связанную с запросом, чтобы она отображала ошибки на основе форм. (Пример кода ниже)

  3. Что касается использования наследования, это будет излишним для этого прецедента, поскольку оно не будет служить какой-либо цели, и было бы лучше, если бы все было просто.

Пример код:

if request.POST: 
    form = MyScheduleForm(request.POST) 
    if form.is_valid(): 
     # Specific stuff with the variables here 
     pass 
else: 
    form = MyScheduleForm() 
+0

Да, я использую аналогичную конструкцию. Проблема в том, что немодельные поля никогда не проверяются, чтобы увидеть, пусты ли они, поэтому, если они пусты, они не генерируют исключение. Поля, которые находятся в модели DO, проверяются, и я получаю сообщение об ошибке, возвращенное обратно в мою форму, если они отсутствуют. – Cyclic

+0

Существует больше, чем кажется на первый взгляд. Я могу запустить вышеуказанный код, и он проверяется! –

0

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

start_datetime=models.DateTimeField(blank=True, null=True) 

Это говорит форме, что она может быть blank , и что поле базы данных может быть null. Это может решить эту проблему.

Почему вы используете ModelForm, если вы пытаетесь включить поля, которые не являются частью модели? ModelForms предназначены для быстрого создания форм, которые напрямую привязаны к вашей модели. Конечно, у них есть различные настройки, но изменение фактических полей мне кажется чем-то, для чего нужна обычная форма.

В противном случае, если вы хотите разделить VIEW формы, а не форму, создайте собственный виджет, чтобы отобразить поле DateTime, например SplitDateTimeWidget. Подклассируйте его и предоставьте свои CHOICES для значений выпадающего списка.

+0

-1 Что делать, если я хочу использовать большую часть этой функции и немного настроить? – Alvaro

+0

@ Alvaro Я упомянул об этом в своем ответе. Есть крючки для определенных настроек, но добавление большого количества полей формы, которые не сопоставляются с полями модели, - это * не *, для каких форм моделей. –

1

Хорошо, я думаю, что я понял это:

На Django 1.2, работает is_valid() запускает проверку MODEL на ModelForms. Я предположил, что поля будут проверяться на пустые значения перед ударом функции clean(), поэтому моя чистая функция не проверяет пустые значения или типы None. В принципе, мой чистый() в моей модели выглядит примерно так:

def clean(self): 
    if self.start_datetime > datetime.now(): 
     raise ValidationError('Start date can\'t be in the future') 

Так что я полагаю, что в основном отвечаю на мой вопрос. Тем не менее, у меня есть еще один вопрос:

Лучше всего проверять пустые значения в модели clean(), или есть лучший способ сделать это? Кажется хакерским для проверки пробелов в модели, а не в ModelForm - это проверка в поле формы, которое должно помечать недостающие входы на обязательных полях?

Спасибо за помощь всем.

+0

Определенно используйте методы 'clean_field' в' ModelForm'. Я очень смущен, потому что, когда я воспроизвожу вашу форму, я получаю 'ValidationError' для дополнительных полей, добавленных в модель ModelForm. Я создал ModelForm, добавил чистый метод, как и ваш, и активирована проверка. Есть ли что-нибудь еще для вашего ModelForm, чем вы показали? –

+0

Я думаю, что проблема здесь (после беспорядка с ней) - если поле пустое, оно никогда не добавляется к cleaned_data, и метод clean_field никогда не запускается. Затем он запускает форму clean() и модель clean(). В моем случае модель clean() вызвала исключение TypeError из-за сравнения, которое я делал в clean(), что привело к сбою моего кода. Я думаю, что эта проблема здесь (исправьте меня, если я ошибаюсь) - пустые значения не вызывают исключения, они просто вызывают ошибку is_valid() и добавляют ошибку в список ошибок. Поскольку у меня была другая ошибка (которая на самом деле выбрала исключение), это вызвало мою проблему – Cyclic

Смежные вопросы