2009-06-20 6 views
3

Ich habe zwei Modelle bevölkern, die wie folgt aussieht:dynamisch Felder in einem formset

class RouteBase(models.Model): 
    base  = models.ForeignKey("Base") 
    route  = models.ForeignKey("Route") 
    sequence = models.IntegerField() 

class Route(models.Model): 
    bases  = models.ManyToManyField("Base", through="RouteBase", blank=True) 
    description = models.TextField(blank=True) 
    #and a few other attributes omitted for brevity 

... dann eine Modelform, die wie folgt aussieht:

class RouteBaseForm(ModelForm): 
    base = forms.ModelChoiceField(queryset=Base.objects.all(), widget=forms.TextInput) 
    sequence = forms.IntegerField(widget=forms.HiddenInput) 

    class Meta: 
     model = RouteBase 

Wie Sie, die Sequenz sehen Widget ist ausgeblendet, da ich möchte, dass dieses Feld automatisch von django bearbeitet wird. Ich möchte, dass der Benutzer die Basis einfach über ein Textfeld eingeben muss. Die Reihenfolge ergibt sich aus der Reihenfolge der Textfelder.

Ich habe für die Erstellung/Bearbeitung alle Basen in der Route eine formset mit dieser Form erstellt:

RouteBaseFormset = inlineformset_factory(Route, RouteBase, form=RouteBaseForm, extra=5,) 

Wenn diese formset erstellt wird, das Sequenzfeld ist leer. Ich muss es mit Werten füllen, bevor ich das Formset speichere (sonst wird es nicht validieren). Ich kann von etwa 4 Möglichkeiten denken über dieses

  1. rechts zu gehen, bevor ich die formset aus der Vorlage zu senden, betreibe ich diesen Code:
 
    i=1 
    for form in formset.forms: 
     form.fields["sequence"].initial = i 
     i += 1 

Dies funktioniert gut, außer für ein Problem . Wenn das Formularset zurück an die Ansicht zum Speichern gesendet wird, werden alle 5 zusätzliche Felder, die mit dem Formset erstellt wurden, mit einem Sequenzwert ausgefüllt. Dies führt zu Problemen, wenn der Benutzer der Route nur 2 oder 3 Basen hinzufügen möchte. Validierungsfehler werden angezeigt, da das erforderliche Feld "base" für dieses Formular leer ist. Ich könnte ein bisschen Code ausführen, nachdem das Formularsatz wurde POSTed, die überprüft, ob eine Basis vorhanden ist, wenn nicht, entfernen Sie die Sequenz, aber wenn ich das tun werde, kann ich auch ...

  1. Führen Sie ein wenig Code aus, wenn das Formset POSTed ist, das prüft, ob eine Base eingegeben wurde. Wenn ja, fügen Sie eine Sequenz hinzu, falls nicht, dann lassen Sie dieses Feld leer. Wenn Sie versuchen, das Formularset .save() zu versuchen, stellen die leeren Werte sicher, dass das bestimmte Formular nicht in der Datenbank gespeichert wird. Das einzige Problem ist, dass ich nichts mit dem Formular tun kann, bis ich .save(commit=False) ausführen, was ich nicht tun kann, weil das Formset nicht validiert. Aber ich könnte ...

  2. Fügen Sie die Sequenzwerte hinzu, indem Sie die request.POST Variable kopieren und manuell die Reihenfolge einstellen, aber das scheint schrecklich hacky.

  3. Ich könnte auch nur blank=True von einem meiner RouteBase Felder entfernen, aber ich will das nicht wirklich tun.

Also was soll ich hier tun?

Antwort

5

Wenn Sie nie vorhaben, dass ein Benutzer das Sequenzfeld bearbeitet und plant, den Wert immer am Back-End zu berechnen, können Sie exclude it from the form, anstatt es ausgeblendet zu haben.

Dann können Sie commit = False verwenden und die Berechnung Ihres Sequenzfeldes nach Bedarf durchführen.

+0

Das scheint nicht zu funktionieren. Es spielt keine Rolle, welche Felder ich ausschließe, wenn es keine Sequenz gibt, wird das Formular nicht validiert und wird daher nicht '.save (commit = False)' – priestc

+1

Sie müssen in Ihrem Modell blank = True setzen für dieses Feld. Da Sie selbst für die Generierung dieses Werts verantwortlich sind (nicht für den Benutzer), benötigen Sie keine Formularüberprüfung. – Harold

-2
newPOST = request.POST.copy() 
i=1 
for index in range(0, int(request.POST["routebase_set-TOTAL_FORMS"])-1): 
    if request.POST["routebase_set-" + str(index) + "-base"]: 
     newPOST["routebase_set-" + str(index) + "-sequence"] = i 
     i += 1 
    else: 
     newPOST["routebase_set-" + str(index) + "-sequence"] = "" 

Ehrlich gesagt scheint dies besser zu funktionieren als mit der Formularvalidierung herumzualbern. Es ist nicht so hacky, wie ich es auch dachte ...

+1

-1 das ist ziemlich hässlich. Der Formularvalidierungsansatz ist viel einfacher und sauberer. –