2011-01-12 11 views
11

tengo un modelo que se parece a:Añadir campos a Django ModelForm que no están en el modelo

class MySchedule(models.Model): 
    start_datetime=models.DateTimeField() 
    name=models.CharField('Name',max_length=75) 

con él viene su 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") 

Básicamente, estoy tratando de Divida el campo DateTime en el modelo en 3 campos de formulario más fáciles de usar: un selector de fecha, un menú desplegable de una hora y un menú desplegable de un minuto. Luego, una vez que obtuve las tres entradas, las vuelvo a ensamblar en un DateTime y las guardo en el modelo.

algunas preguntas:

1) ¿Es ésta totalmente la forma equivocada de hacerlo? No quiero crear campos en el modelo por horas, minutos, etc., ya que básicamente todo son solo datos intermedios, así que me gustaría una manera de dividir el campo DateTime en subcampos.

2) La dificultad que me encuentro es cuando el campo de fecha de inicio está en blanco - parece que nunca se verifica por falta de nitidez, y acaba arrojando un TypeError más tarde cuando el programa espera una fecha y obtiene ninguno ¿Dónde comprueba Django las entradas en blanco y genera el error que eventualmente vuelve al formulario? ¿Es esta mi responsabilidad? Si es así, ¿cómo lo hago, ya que no evalúa clean_startdate() ya que startdate no está en el modelo?

3) ¿Hay alguna forma mejor de hacer esto con la herencia? ¿Tal vez heredar MyScheduleForm en BetterScheduleForm y agregar los campos allí? ¿Cómo haría esto? (He estado jugando con ello durante más de una hora y parece que no puede conseguirlo)

¡Gracias!

[Editar:] quedado fuera de la self.cleaned_data retorno - perdido en el copiar/pegar originalmente

+0

En general, ModelForm puede contener los campos que desee. Es como una forma normal en ese sentido. La única preocupación es que necesitará implementar los datos iniciales, los métodos clean() apropiados y el método save() apropiado si esos campos no existen en el modelo, ya que un ModelForm intenta generar esos elementos de forma auto-mágica usando el modelo. – Cerin

Respuesta

0

1: No creo que esté mal, porque tiene algunas cosas muy específicas pasando allí:

  • entradas de tiempo específicos (mediodía, terminando en 17:00 ..) incrementos
  • 15 minutos para startminutes

2: actualización: comentar a continuación dice que su campo debe ser required=True de forma predeterminada. Es cierto, debería obtener un ValidationError con su formulario si el campo se deja en blanco.

¿Puedes publicar el TypeError de lo que hablas? ¿Está sucediendo fuera del bloque clean()? Porque si no devuelve cleaned_data desde su función de limpieza como en su ejemplo, su formulario no tendrá ningún dato con el que trabajar aunque lo compruebe inicialmente al no generar ValidationErrors.

De todos modos, puede explorar los métodos clean_ para validación de campo.

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: ¿Puede aclarar aquí lo que estamos tratando de hacer con la herencia? Parece que las definiciones de su campo son muy específicas para este formulario, por lo que pertenece aquí en el MyScheduleForm.La herencia es para volver a usar el código:)

Si está buscando reutilizar esto para múltiples DateTimeField s, sí puede usar la herencia del formulario. Se podría definir un ModelForm como que tiene ahora, una subclase, y anular de Meta los padres como se muestra aquí en la documentación para usarlo en varios modelos: http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#form-inheritance

También me echa un vistazo a cómo el Django hace su SplitDateTimeWidget (compruebe la fuente): http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.SplitDateTimeWidget

¡Hay algunos otros widgets de fecha y hora divididos 'de terceros' que vale la pena echar un vistazo a los interwebs también!

+0

required = True es la configuración predeterminada para los campos de formulario django. –

+0

Buen punto, pero entonces no debería tener el problema con el n. ° 2. Me pregunto por qué ese campo no es válido. hmm –

+0

Gracias por su respuesta - aquí están algunas respuestas a sus preguntas: 1) Sé que se requiere que el default = true. El problema es que si los campos que no son modelo (fecha de inicio, hora de inicio, etc.) se dejan en blanco, no arroja una excepción y devuelve la información de "campo faltante" a mi formulario. Quiero que comprobar si hay vacuidad y balk si hay un campo en blanco, pero parece perderse este hasta que el campo en blanco provoca problemas más adelante en la limpieza() 2) He intentado añadir una función clean_startdate(), pero parece nunca ser llamado Sin embargo, se llama a las funciones clean_ para los campos de mi modelo DO. – Cyclic

1
  1. Si yo fuera tú, me habría utilizado el customised Django-admin date/time widget(s) para introducir entradas de fecha/hora.

  2. En cuanto a la validación del formulario, asegúrese de pasar el formulario asociado con la solicitud para que aparezca errores basados ​​en formularios. (Código de ejemplo a continuación)

  3. En cuanto al uso de la herencia, sería excesivo para este caso de uso, ya que no servirá para nada y sería mejor mantener las cosas simples.

Código de ejemplo:

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

Sí, estoy usando una construcción similar. El problema es que los campos que no son modelos nunca parecen verificarse para ver si están en blanco, por lo que si están en blanco, no lanzan una excepción. Los campos que están en el modelo DO se comprueban, y recibo un error que se devuelve a mi formulario si faltan – Cyclic

+0

. Hay más de lo que parece. Puedo ejecutar el código anterior y se valida! –

0

Para campos de formulario que pueden contener valores en blanco, debe declarar el campo de la siguiente manera:

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

Esto le dice a la forma que puede ser blank y que el campo de la base de datos puede ser null. Eso puede solucionar ese problema.

¿Por qué usa un ModelForm si intenta incluir campos que no forman parte del Modelo? ModelForms está diseñado para crear rápidamente formularios que se unen directamente a su modelo. Por supuesto, tienen varias personalizaciones, pero cambiar los campos reales me parece algo para lo que es un formulario regular.

De lo contrario, si solo desea dividir la VISTA del formm, no el formulario en sí, cree un widget personalizado para mostrar el campo DateTime, como SplitDateTimeWidget. Subclass it y proporcione sus OPCIONES para los valores del menú desplegable.

+0

-1 ¿Qué sucede si quiero usar la mayoría de esta funcionalidad y personalizarla un poco? – Alvaro

+0

@ Alvaro Lo mencioné en mi respuesta. Hay ganchos para ciertas personalizaciones, pero agregar un montón de campos de formulario que no se asignan a los campos del modelo es * no * para qué sirven los formularios del modelo. –

1

Ok, creo que lo he descubierto:

A partir de Django 1.2, corriendo is_valid() desencadena la validación del modelo en ModelForms. Había asumido que los campos se verificarían en busca de valores en blanco ANTES de pulsar la función clean() del modelo, por lo que mi función de limpieza no verifica los valores en blanco ni los tipos None. Básicamente, mi limpieza() en mi modelo se ve algo así como:

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

Supongo que en su mayoría responderé a mi pregunta. Sin embargo, tengo 1 pregunta restante:

¿Es mejor verificar los valores en blanco en el modelo clean(), o hay una mejor manera de hacerlo? Parece que hackear para verificar si hay espacios en blanco en el modelo en lugar de en el ModelForm. ¿Se supone que la validación en el campo de formulario marca las entradas faltantes en los campos obligatorios?

Gracias por la ayuda de todos.

+0

Definitivamente utilice los métodos 'clean_field' en' ModelForm'. Estoy muy confundido porque cuando reproduzco tu formulario, obtengo un 'ValidationError' para agregar campos adicionales a mi ModelForm. Creé un ModelForm, agregué un método limpio como el tuyo y activé la validación. ¿Hay algo más en tu ModelForm que el que has mostrado? –

+0

Creo que el problema aquí (después de jugar con él): si el campo está en blanco, nunca se agrega a datos limpios, y el método clean_field nunca se ejecuta. A continuación, ejecuta el formulario clean() y el modelo clean(). En mi caso, el modelo clean() provocó una excepción TypeError debido a una comparación que estaba realizando en clean(), lo que provocó que fallara mi código. Creo que este es el problema aquí (corrígeme si me equivoco): los valores en blanco no desencadenan excepciones, solo provocan que is_valid() falle y agregan un error a la lista de errores. Como tuve otro error (que en realidad DIC lancé un excpt), eso causó mi problema – Cyclic

Cuestiones relacionadas