2011-01-12 10 views
11

ich ein Modell, das wie folgt aussieht:, Ich versuche Grundsätzlichhinzufügen Felder Django Modelform, die nicht im Modell ist

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") 

zu:

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

Mit ihm kommt seine Modelform brechen Sie das DateTime-Feld im Modell in 3 einfacher zu verwendende Formularfelder auf - eine Datumsauswahl, eine Stunden-Dropdown-Liste und eine Minuten-Dropdown-Liste. Nachdem ich die drei Eingaben erhalten habe, setze ich sie zu einer DateTime zusammen und speichere sie im Modell.

Ein paar Fragen:

1) Ist der völlig der falsche Weg, um es zu tun? Ich möchte keine Felder im Modell für Stunden, Minuten usw. erstellen, da dies alles nur zwischenzeitliche Daten sind. Daher möchte ich eine Möglichkeit, das DateTime-Feld in Unterfelder zu zerlegen.

2) Die Schwierigkeit, auf die ich stoße, ist, wenn das Feld startdate leer ist - es scheint, als würde es nie auf Nichtleerheit geprüft werden, und es endet nur später ein TypeError, wenn das Programm ein Datum erwartet und bekommt keine. Wo überprüft Django auf leere Eingaben und löst den Fehler aus, der schließlich in das Formular zurückkehrt? Ist das meine Verantwortung? Wenn ja, wie mache ich das, da es clean_startdate() nicht auswertet, da das Startdatum nicht im Modell ist.

3) Gibt es einen besseren Weg, dies mit Vererbung zu tun? Vielleicht das MyScheduleForm in BetterScheduleForm erben und die Felder dort hinzufügen? Wie würde ich das tun? (Ich habe über eine Stunde damit herum gespielt und kann es anscheinend nicht bekommen)

Danke!

[Edit:] die Rückkehr self.cleaned_data links aus - verloren sie in der Copy/Paste ursprünglich

+0

Im Allgemeinen kann das ModelForm enthalten, welche Felder Sie möchten. Es ist wie eine normale Form in dieser Hinsicht. Die einzige Sorge ist, dass Sie die Anfangsdaten, die entsprechenden clean() -Methoden und die entsprechende save() -Methode implementieren müssen, wenn diese Felder nicht im Modell vorhanden sind, da ein ModelForm versucht, diese Dinge automatisch zu erzeugen das Model. – Cerin

Antwort

0

1: Ich glaube nicht, es ist falsch, weil Sie einige sehr spezielle Sachen da los haben:

  • Spezifische Zeiteinträge (Mittag, um 05.00 Uhr endet ..)
  • Schritten von 15 Minuten für startminutes

2: Update: Kommentar unten sagt Ihr Feldsein solltestandardmäßig. Es ist wahr, Sie sollten eine ValidationError mit Ihrem Formular erhalten, wenn das Feld leer gelassen wird.

Können Sie die TypeError, von der Sie sprechen, posten? Tritt es außerhalb des clean() Blocks auf? Denn wenn Sie nicht wie in Ihrem Beispiel cleaned_data von Ihrer Bereinigungsfunktion zurückgeben, verfügt Ihr Formular über keine Daten, mit denen es arbeiten kann, selbst wenn es anfänglich auscheckt, indem es keine ValidationErrors anhebt.

Wie auch immer, Sie können die clean_ Methoden für pro Feld Validierung erkunden.

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: Können Sie klären Sie hier, was Sie mit Vererbung zu tun versuchen? Es sieht so aus, als ob Ihre Felddefinitionen sehr spezifisch für dieses Formular sind, also gehört es genau hier in die MyScheduleForm.Vererbung ist für die Wiederverwendung von Code:)

Wenn Sie versuchen, dies für mehrere DateTimeField s wiederzuverwenden, können Sie ja die Vererbung von Formularen verwenden. Sie könnten eine ModelForm definieren, wie Sie jetzt haben, eine Unterklasse es, und überschreiben die Eltern Meta wie hier in der Dokumentation gezeigt, dass es auf mehrere Modelle zu verwenden: http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#form-inheritance

ich auch heraus überprüfen würde, wie die django seine SplitDateTimeWidget tut (überprüfen Sie die Quelle): http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.SplitDateTimeWidget

Es gibt einige andere '3rd Party' split Datum Zeit Widgets einen Blick auf die Interweb auch wert!

+0

erforderlich = True ist die Standardeinstellung für Django-Formularfelder. –

+0

Guter Punkt, aber dann sollte er nicht das Problem mit # 2 haben. Ich frage mich, warum dieses Feld nicht validiert? hmm –

+0

Vielen Dank für Ihre Antwort - hier sind ein paar Antworten auf Ihre Fragen: 1) Ich weiß, dass der Standard erforderlich ist = True. Das Problem ist, wenn die Nicht-Modell-Felder (Startdatum, Starthour, usw.) leer gelassen werden, löst es keine Ausnahme aus und gibt die Information "fehlendes Feld" an mein Formular zurück. Ich will, dass es auf Leerheit und Balken überprüft, wenn es ein leeres Feld gibt, aber es scheint zu fehlen, bis das leere Feld später Probleme in der sauberen() 2) Ich habe versucht, eine clean_startdate() -Funktion, aber es scheint niemals angerufen werden. Die clean_-Funktionen für die Felder in meinem Modell werden jedoch aufgerufen. – Cyclic

1
  1. Wenn ich Sie wäre, würde ich die customised Django-admin date/time widget(s) Einträge Datum/Zeit nicht benutzt haben für die Eingabe.

  2. In Bezug auf die Formularüberprüfung sollten Sie sicherstellen, dass Sie das mit der Anforderung verknüpfte Formular übergeben, damit formularbasierte Fehler angezeigt werden. (Beispielcode unten)

  3. Bei der Verwendung der Vererbung wäre es ein Overkill für diesen Anwendungsfall, da es keinen Zweck erfüllt und es besser wäre, die Dinge einfach zu halten.

Beispielcode:

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

Ja, ich benutze ein ähnliches Konstrukt. Das Problem ist, dass nicht modellierte Felder niemals überprüft werden, um zu sehen, ob sie leer sind. Wenn sie leer sind, werfen sie keine Ausnahme auf. Felder, die sich im Modell DO befinden, werden überprüft, und es wird eine Fehlermeldung an mein Formular zurückgegeben, wenn sie fehlen – Cyclic

+0

Es gibt mehr, als es auf den ersten Blick erkennen lässt. Ich kann den obigen Code ausführen und es wird validiert! –

0

Für Formularfelder, die leere Werte enthalten können, müssen Sie das Feld wie folgt deklarieren:

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

Dieses Formular sagt, dass es sein kann, blank und dass das Datenbankfeld null sein kann. Das könnte dieses Problem beheben.

Warum verwenden Sie eine ModelForm, wenn Sie Felder einfügen möchten, die nicht Teil des Modells sind? ModelForms wurden entwickelt, um schnell Formulare zu erstellen, die direkt an Ihr Modell binden. Natürlich haben sie verschiedene Anpassungen, aber das Ändern der tatsächlichen Felder scheint mir etwas zu sein, für das ein reguläres Formular ist.

Andernfalls, wenn Sie nur die Ansicht des Formulars teilen möchten, nicht das Formular selbst, erstellen Sie ein benutzerdefiniertes Widget zum Anzeigen des DateTime-Felds, z. B. das SplitDateTimeWidget. Subklassifizieren Sie es und geben Sie Ihre Auswahl für die Werte des Dropdowns an.

+0

-1 was, wenn ich die meisten dieser Funktionalität verwenden und ein wenig anpassen möchte? – Alvaro

+0

@Alvaro Ich erwähnte das in meiner Antwort. Es gibt Hooks für bestimmte Anpassungen, aber das Hinzufügen einer ganzen Menge von Formularfeldern, die keinen Modellfeldern zugeordnet sind, ist * nicht *, für welche Modellformen es sich handelt. –

1

Ok, ich glaube, ich es herausgefunden:

Ab Django 1.2, läuft is_valid() löst Modellvalidierung auf ModelForms. Ich hatte angenommen, dass Felder auf leere Werte überprüft werden würden, BEVOR die Funktion clean() des Modells angeklickt wird, so dass meine clean-Funktion nicht nach Leerwerten oder None-Typen sucht. Grundsätzlich sieht mein sauberes() in meinem Modell so aus:

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

Also nehme ich an, dass meistens meine Frage beantwortet. Ich habe jedoch noch 1 Frage:

Ist es am besten, im Modell clean() nach leeren Werten zu suchen, oder gibt es einen besseren Weg, dies zu tun? Scheint hashish, anstatt im ModelForm nach Leerzeichen im Modell zu suchen - soll die Validierung im Formularfeld fehlende Eingaben in Pflichtfeldern markieren?

Danke für die Hilfe aller.

+0

Verwenden Sie auf jeden Fall die 'clean_field' Methoden auf' ModelForm'. Ich bin sehr verwirrt, denn wenn ich dein Formular reproduziere, erhalte ich einen 'ValidationError' für zusätzliche Felder, die zu meiner ModelForm hinzugefügt werden. Ich habe eine ModelForm erstellt, eine saubere Methode wie deine hinzugefügt und die Validierung ausgelöst. Gibt es noch etwas anderes zu deiner ModelForm als du gezeigt hast? –

+0

Ich denke, das Problem hier (nach herumspielen damit) - wenn das Feld leer ist, wird es nie zu cleaned_data hinzugefügt, und die clean_field-Methode wird nie ausgeführt. Anschließend wird das Formular clean() und das Modell clean() ausgeführt. In meinem Fall verursachte das Modell clean() eine TypeError-Ausnahme aufgrund eines Vergleichs, den ich in clean() machte, was dazu führte, dass mein Code fehlschlug. Ich denke, dieses Problem hier (korrigieren Sie mich, wenn ich falsch liege) - leere Werte lösen keine Ausnahmen aus, sie verursachen nur, dass is_valid() fehlschlägt und sie fügen einen Fehler zur Fehlerliste hinzu. Da ich einen weiteren Fehler hatte (der tatsächlich eine EXPT geworfen hat), hat das mein Problem verursacht – Cyclic

Verwandte Themen