2017-08-19 3 views
1

DjangoでModelFormを使用してデータベースのモデルのEditフォームを作成しています。ユーザーが1つのフィールドのみを編集したい場合は、フォームの各フィールドはオプションです。空のフィールドでモデルデータを保存する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リクエストの値を持っているかを明示的にチェックしようとしましたが、違いは見られませんでした。ドキュメントはModeFormは、フォームの送信には存在しない値のためにこれらを使用すると言うように私もPlayerモデルの任意のデフォルト値を持っていない

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 

:saveメソッドをオーバーライドすることで

試み。

編集:ここでは

が全体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]をので、ここでは、溶液中で、私はそれが役に立つかもしれないと私はここにそれを置くだろう考え出し他の人(私は確かにこれから少し学んだ)。

モデルフォームの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']を構築することにより、代わりにsave() または引数update_field

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

update()メソッドを使用することができます。

:(フォームでこの試みをしてコメントアウト)保存メソッドをオーバーライドすることなく

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

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

EDIT:

それも、あなたが試した理解と協力すべきです

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

これは正常に動作します。私はそれが最良の方法だとは分かりませんが、うまくいくはずです。

関連する問題