2017-08-19 3 views
1

Ich erstelle ein Bearbeitungsformular für ein Modell in meiner Datenbank mit einem ModelForm in Django. Jedes Feld im Formular ist optional, da der Benutzer möglicherweise nur ein Feld bearbeiten möchte.ModelForm Modelldaten mit leeren Feldern speichern

Das Problem, das ich habe, ist, dass, wenn ich save() in der Ansicht aufrufen, werden alle leeren Felder über die ursprünglichen Werte der Instanz gespeichert werden (zB wenn ich nur einen neuen first_name eingeben, die last_name und ecf_code Felder eine leere Zeichenfolge speichern in dem entsprechenden Beispiel)

die Form:.

class EditPlayerForm(forms.ModelForm): 

    class Meta: 
     model = Player 
     fields = ['first_name', 'last_name', 'ecf_code'] 

    def __init__(self, *args, **kwargs): 
     super(EditPlayerForm, self).__init__(*args, **kwargs) 
     self.fields['first_name'].required = False 
     self.fields['last_name'].required = False 
     self.fields['ecf_code'].required = False 

die Ansicht:

def view(request, player_pk = ''): 

    edit_player_form = forms.EditPlayerForm(auto_id="edit_%s") 

    if "edit_player_form" in request.POST: 

     if not player_pk: 

      messages.error(request, "No player pk given.") 

     else: 

      try: 

       selected_player = Player.objects.get(pk = player_pk) 

      except Player.DoesNotExist: 

       messages.error(request, "The selected player could not be found in the database.") 
       return redirect("players:management") 

      else: 

       edit_player_form = forms.EditPlayerForm(
        request.POST, 
        instance = selected_player 
       ) 

       if edit_player_form.is_valid(): 

        player = edit_player_form.save() 
        messages.success(request, "The changes were made successfully.") 
        return redirect("players:management") 

       else: 
        form_errors.convert_form_errors_to_messages(edit_player_form, request) 

    return render(
     request, 
     "players/playerManagement.html", 
     { 
      "edit_player_form": edit_player_form, 
      "players": Player.objects.all(), 
     } 
    ) 

Ich habe versucht, die save() Methode des Formulars zu überschreiben, um explizit zu überprüfen, welche Felder Werte in der POST Anfrage haben, aber das schien auch keinen Unterschied zu machen.

Versuch, die Speichermethode bei Überschreiben:

def save(self, commit = True): 

    # Tried this way to get instance as well 
    # instance = super(EditPlayerForm, self).save(commit = False) 

    self.cleaned_data = dict([ (k,v) for k,v in self.cleaned_data.items() if v != "" ]) 

    try: 
     self.instance.first_name = self.cleaned_data["first_name"] 
    except KeyError: 
     pass 

    try: 
     self.instance.last_name = self.cleaned_data["last_name"] 
    except KeyError: 
     pass 

    try: 
     self.instance.ecf_code = self.cleaned_data["ecf_code"] 
    except KeyError: 
     pass 


    if commit: 
     self.instance.save() 


    return self.instance 

ich auch haben keine Standardwerte für das Player Modell wie die Docs sagen die ModeForm diese für Werte fehlen in Form Vorlage verwenden.

EDIT:

Hier ist die ganze EditPlayerForm:

class EditPlayerForm(forms.ModelForm): 


    class Meta: 
     model = Player 
     fields = ['first_name', 'last_name', 'ecf_code'] 

    def __init__(self, *args, **kwargs): 
     super(EditPlayerForm, self).__init__(*args, **kwargs) 
     self.fields['first_name'].required = False 
     self.fields['last_name'].required = False 
     self.fields['ecf_code'].required = False 


    def save(self, commit = True): 

     # If I print instance variables here they've already 
     # been updated with the form values 

     self.cleaned_data = [ k for k,v in self.cleaned_data.items() if v ] 

     self.instance.save(update_fields = self.cleaned_data) 

     if commit: 

      self.instance.save() 

     return self.instance 

EDIT:

Ok, so ist hier die Lösung, ich dachte ich es würde hier, wie es nützlich sein könnte, andere Leute (ich habe sicherlich ein bisschen davon gelernt).

So stellt sich heraus, dass die is_valid() Methode des Modells Formular tatsächlich die Änderungen an der Instanz, die Sie in das Formular übergeben, bereit für die save() Methode, um sie zu speichern. Also, um dieses Problem zu beheben, ich verlängerte die clean() Methode des Formulars:

def clean(self): 

    if not self.cleaned_data.get("first_name"): 
     self.cleaned_data["first_name"] = self.instance.first_name 

    if not self.cleaned_data.get("last_name"): 
     self.cleaned_data["last_name"] = self.instance.last_name 

    if not self.cleaned_data.get("ecf_code"): 
     self.cleaned_data["ecf_code"] = self.instance.ecf_code 

Diese im Grunde prüft nur um zu sehen, wenn die Felder leer sind und wenn ein Feld leer ist, füllen Sie es mit dem vorhandenen Wert aus dem gegebene Instanz. clean() wird aufgerufen, bevor die Instanzvariablen mit den neuen Formularwerten festgelegt werden. Auf diese Weise wurden alle leeren Felder tatsächlich mit den entsprechenden vorhandenen Instanzdaten gefüllt.

Antwort

1

Sie könnten vielleicht die update() Methode anstelle von save() oder das Argument update_field

self.instance.save(update_fields=['fields_to_update']) 

durch den Aufbau der Liste ['fields_to_update'] nur mit den nicht leeren Werte.

Es sollte auch mit dem Verständnis arbeiten Sie versucht haben:

self.cleaned_data = [ k for k,v in self.cleaned_data.items() if v ] 

self.instance.save(update_fields=self.cleaned_data) 

EDIT:

Ohne die Methode speichern überschreiben (und diesen Versuch zu kommentieren Hilfen in Form):

not_empty_data = [ k for k,v in edit_player_form.cleaned_data.items() if v ] 
print(not_empty_data) 
player = edit_player_form.save(update_fields=not_empty_data) 
+0

Vielen Dank für die Hilfe! Ich habe dies in die 'save()' Methode des Formulars eingefügt, aber es funktioniert immer noch nicht, wenn ich die Variablen der Instanz am Anfang der Speichermethode im Formular drucke, wurden sie bereits auf die leeren Zeichenkettenwerte gesetzt 'instance.save()' wird sogar in der Methode des Formulars aufgerufen (hoffe, dass das Sinn ergab) – RHSmith159

+0

@ RHSmith159 Sorry, das half dir nicht, könntest du das Formular 'EditPlayerForm' zu der Frage hinzufügen? – PRMoureu

+1

sicher, ich füge es jetzt – RHSmith159

1

Sie könnten die Werte prüfen, wenn es in Ihrer Ansicht nicht leer ist, ohne zu überschreiben save()

if edit_player_form.is_valid(): 
    if edit_player_form.cleaned_data["first_name"]: 
     selected_player.first_name = edit_player_form.cleaned_data["first_name"] 
    if edit_player_form.cleaned_data["last_name"]: 
     selected_player.last_name= edit_player_form.cleaned_data["last_name"] 
    if edit_player_form.cleaned_data["ecf_code"]: 
     selected_player.ecf_code= edit_player_form.cleaned_data["ecf_code"] 
    selected_player.save() 

Dies sollte gut mit dem funktionieren, was Sie wollen. Ich bin mir nicht sicher, ob es der beste Weg ist, es zu tun, aber es sollte gut funktionieren.

Verwandte Themen