1. ホーム
  2. python

Django の ModelForm で save メソッドをオーバーライドする

2023-10-04 22:25:20

質問

をオーバーライドするのに苦労しています。 ModelForm 保存メソッドをオーバーライドするのに問題があります。これは私が受け取っているエラーです。

Exception Type:     TypeError  
Exception Value:    save() got an unexpected keyword argument 'commit'

私の意図は、フォームが3つのフィールドのために多くの値を送信し、次にそれらのフィールドの各組み合わせのためにオブジェクトを作成し、それらのオブジェクトの各々を保存することです。正しい方向への助けの後押しがあれば最高です。

ファイル models.py

class CallResultType(models.Model):
    id = models.AutoField(db_column='icontact_result_code_type_id', primary_key=True)
    callResult = models.ForeignKey('CallResult', db_column='icontact_result_code_id')
    campaign = models.ForeignKey('Campaign', db_column='icampaign_id')
    callType = models.ForeignKey('CallType', db_column='icall_type_id')
    agent = models.BooleanField(db_column='bagent', default=True)
    teamLeader = models.BooleanField(db_column='bTeamLeader', default=True)
    active = models.BooleanField(db_column='bactive', default=True)

ファイル forms.py

from django.forms import ModelForm, ModelMultipleChoiceField
from callresults.models import *

class CallResultTypeForm(ModelForm):
    callResult = ModelMultipleChoiceField(queryset=CallResult.objects.all())
    campaign = ModelMultipleChoiceField(queryset=Campaign.objects.all())
    callType = ModelMultipleChoiceField(queryset=CallType.objects.all())

    def save(self, force_insert=False, force_update=False):
        for cr in self.callResult:
            for c in self.campain:
                for ct in self.callType:
                    m = CallResultType(self) # this line is probably wrong
                    m.callResult = cr
                    m.campaign = c
                    m.calltype = ct
                    m.save()

    class Meta:
        model = CallResultType

ファイル admin.py

class CallResultTypeAdmin(admin.ModelAdmin):
    form = CallResultTypeForm

どのように解決するのですか?

あなたの save には、引数として commit . もし何かがあなたのフォームを上書きしたり、保存されているものを変更したい場合は、次のようになります。 save(commit=False) を実行し、出力を修正し、そしてそれ自体を保存します。

また、モデルフォームは保存しているモデルを返さなければなりません。通常、モデルフォームの save は次のようなものになります。

def save(self, commit=True):
    m = super(CallResultTypeForm, self).save(commit=False)
    # do custom stuff
    if commit:
        m.save()
    return m

読む save メソッド .

最後に、このモデルフォームの多くは、アクセス方法のせいで動作しません。代わりに self.callResult を使用する必要があります。 self.fields['callResult'] .

アップデイト : ご回答を受けて。

脇です。 なぜ、単に ManyToManyField を使うようにすればいいんじゃないでしょうか?冗長なデータを保存しているように見えるし、自分自身(と私)の仕事を増やしているように見えます。 :P ).

from django.db.models import AutoField  
def copy_model_instance(obj):  
    """
    Create a copy of a model instance. 
    M2M relationships are currently not handled, i.e. they are not copied. (Fortunately, you don't have any in this case)
    See also Django #4027. From http://blog.elsdoerfer.name/2008/09/09/making-a-copy-of-a-model-instance/
    """  
    initial = dict([(f.name, getattr(obj, f.name)) for f in obj._meta.fields if not isinstance(f, AutoField) and not f in obj._meta.parents.values()])  
    return obj.__class__(**initial)  

class CallResultTypeForm(ModelForm):
    callResult = ModelMultipleChoiceField(queryset=CallResult.objects.all())
    campaign = ModelMultipleChoiceField(queryset=Campaign.objects.all())
    callType = ModelMultipleChoiceField(queryset=CallType.objects.all())

    def save(self, commit=True, *args, **kwargs):
        m = super(CallResultTypeForm, self).save(commit=False, *args, **kwargs)
        results = []
        for cr in self.callResult:
            for c in self.campain:
                for ct in self.callType:
                    m_new = copy_model_instance(m)
                    m_new.callResult = cr
                    m_new.campaign = c
                    m_new.calltype = ct
                    if commit:
                        m_new.save()
                    results.append(m_new)
         return results

これによって CallResultTypeForm を継承することができます。