2017-08-19 68 views
1

我在Django中使用ModelForm爲我的數據庫中的模型構建了一個編輯表單。表單中的每個字段都是可選的,因爲用戶可能只想編輯一個字段。ModelForm在模型數據上保存空字段

我遇到的問題是,當我在查看通話save(),任何空字段被保存在實例的原始值(例如,如果我只輸入一個新first_name,則last_nameecf_code領域將節省一個空字符串在相應的實例)

形式:

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 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(), 
     } 
    ) 

我試着重寫表格的save()方法來明確地檢查哪些字段在POST請求中有值,但這似乎也沒有任何區別。

嘗試在重寫保存方法:

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 

我也沒有對Player模型的任何默認值,文檔說的ModeForm將使用這些在表單提交缺席值。

編輯:

這裏是整個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 

編輯:

好了,所以這裏是解決方案,我想我把它放在這裏,因爲它可能是有用的其他人(我肯定從中學到了一點)。

因此,事實證明,模型表單的is_valid()方法實際上會更改您傳遞到表單的實例,爲save()方法保存它們做好準備。因此,爲了解決這個問題,我伸出形式的clean()方法:

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 

這基本上只是檢查是否字段爲空,如果一個字段爲空,從現有的值填充給定實例。在使用新表單值設置實例變量之前調用clean(),這樣,任何空字段實際上都會填充相應的現有實例數據。

回答

1

也許你可以只用不爲空值,構建列表['fields_to_update']使用update()方法,而不是save() 或參數update_field

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

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

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

編輯:

應該即使你已經嘗試了理解工作

沒有覆蓋的保存方法(和評論表單中的這種嘗試):

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

非常感謝您的幫助!我把它放到窗體的save()方法中,但是它仍然不起作用,如果我在窗體的save方法開始時打印實例的變量,它們已經被設置爲空的字符串值'instance.save()'甚至在窗體的方法中調用(希望是有道理的) – RHSmith159

+0

@ RHSmith159對不起,這不是幫助你,你可以添加表單'EditPlayerForm'的問題? – PRMoureu

+1

肯定的事情,我現在將它添加 – RHSmith159

1

您可以檢查值,如果它不是空的在您的視圖中沒有覆蓋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() 

這應該適用於你想要的。我不確定這是否是最好的方法,但它應該可以正常工作。