2

1 つ以上のモデルを持つことができるシステムがあります。manytomany フィールドを使用して、データベースでこの関係をモデル化しました。以下のコードは、システムとそれに関連するメソッドを 1 つのフォームで編集するためのものです。

フォームに入力して送信を押すことによる新しいメソッドの追加は、初回のみ機能します。その後、小さな変更を加えて再度送信すると、次のメッセージが表示されます (以下のコードによって生成されます)。

METHODFORMSET.ERRORS: [{}, {'name': [u'Method with this Name already exists.']}]

これは、名前フィールドが一意であるという事実によって引き起こされますが、POST データを使用して methodformset インスタンスを生成しているにもかかわらず、新しいレコードを作成するのではなく、更新する必要があります...

この動作は、テーブルに既に存在するものではなく、最後に追加されたメソッド インスタンスにのみ適用されることに注意してください。

関連するコードは次のとおりです。誰かが私が間違っていることを教えてもらえますか?

def sysedit(request, sys_id):

    system = System.objects.get(id=sys_id)
    MethodFormSet = modelformset_factory(Method, form=MethodForm)

    post = None
    if request.POST:
        post = request.POST.copy()
        if 'add_method' in request.POST:
            post['method-TOTAL_FORMS'] = repr(int(
                                                post['method-TOTAL_FORMS'])+ 1)

    systemform = SystemForm(data=post, instance=system)

    methodformset = MethodFormSet(data=post, prefix='method',
            queryset=Method.objects.filter(id__in=system.method.all()))

    if methodformset.is_valid():
        mfs = methodformset.save()
        print 'SAVED-method', mfs
        for mf in mfs:
            if systemform.is_valid():
                sp = systemform.save(mf)
                print 'SYSTEM', sp
            else:
                print 'SYSFORMSET.ERRORS:', systemform.errors
    else:
        print 'METHODFORMSET.ERRORS:', methodformset.errors

    return render_to_response('sysedit.html', 
            {'systemform': systemform, 
            'methodformset': methodformset, 
            'system': system},
            context_instance=RequestContext(request))


class System(models.Model):
    method = models.ManyToManyField(Method)
    ...

class Method(models.Model):
    name = models.CharField(unique=True)
    ...

class MethodForm(ModelForm):
    class Meta:
        model = Method

class SystemForm(ModelForm):
    def save(self, new_method=None, commit=True, *args, **kwargs):
        m = super(SystemForm, self).save(commit=False, *args, **kwargs)
        if new_method:
            m.method.add(new_method)
        if commit:
            m.save()
        return m

    class Meta:
        model = System
        exclude = ('method')

[セルグザックの回答後に編集]:

問題は、エラーにどう対処するかではなく、そもそもMethod with this name already existsエラーが発生しないようにすることです。実際の問題は、modelformsets が新しいフォームを処理する方法に関係があると思います。どういうわけか、既に存在するかどうかに関係なく、常に最後のフォームセットの新しいインスタンスを作成しようとするようです。

したがって、最後のフォームセットが追加された後に新しいフォームセットを追加しないと、モデルフォームセットは最後のフォームセットを再作成しようとします (前回の送信で作成されたばかりでも)。

最初の状況では、methodformset に 1 つの有効な Method インスタンスと 1 つの新しいバインドされていないインスタンスがあります。次に、フォームに入力して保存をクリックすると、両方のメソッドが検証され、2 番目のメソッドがバインドされ、テーブルに保存されます。これまでのところすべて順調ですが、2回目に保存するとエラーが発生します。おそらくこれは、method-TOTAL_FORMS=2 および method-INITIAL_FORMS=1 という事実に関係しています。これにより、modelformset が 2 番目のメソッドで作成を強制する可能性がありますか?

誰でもこれを確認/拒否できますか?

[コードを見ていない週末の後に編集]:

この問題は、フォームをビューに保存し、保存後に元の methodformset インスタンス (保存から) をテンプレートに送信しているために発生します。この問題は、POST データではなくクエリセットを使用して、保存にmodelformset を再インスタンス化することで解決できます。

したがって、このようなエラーを防ぐための一般的なルールは、保存後に別のページに移動する (完全に回避する) か、上記の解決策を使用することです。

これを THE ソリューションとして投稿する前に、さらにテストを行う必要があります。

4

2 に答える 2

0

保存後にモデルフォームセットを再インスタンス化することで問題を解決しました(質問の下部にある編集を参照)

于 2012-08-21T08:27:46.460 に答える
0

フォームセットを保存するときに、各フォームを検証できます。簡単な例(コードに似たもの)を作成しましたが、うまく機能します。そのような名前のオブジェクトがない場合は新しいオブジェクトを作成し、それ以外の場合は既存のオブジェクトを編集します。

モデル オブジェクトを編集するにはフォームが必要です。

class EditMethodForm( forms.ModelForm ):
   class Meta:
      model = Method
      exclude = ( 'name', )

次に、 methodformset.is_valid() の代わりに次のことを行います:

for methodform in methodformset:
    try:
        instance = Method.objects.get( name = request.POST[ 'name' ] )
    except Method.DoesNotExist:
        methodform.save()
    else:
        editmethodform = EditMethodForm( request.POST, instance = instance )
        if editmethodform.is_valid():
            editmethodform.save()

コードにはいくつかの追加機能があります。動作原理を示します。解決策を理解するだけで十分ですか?

于 2012-07-27T07:59:19.390 に答える