122

サポート チケット追跡アプリを構築しており、1 つのページから作成したいモデルがいくつかあります。チケットは、ForeignKey を介して Customer に属します。Notes は、ForeignKey を介してチケットにも属します。顧客を選択するオプション(これはまったく別のプロジェクトです)または新しい顧客を作成してからチケットを作成し、最後に新しいチケットに割り当てられたメモを作成するオプションが欲しいです。

私は Django にかなり慣れていないので、毎回新しい機能を試して、繰り返し作業する傾向があります。ModelForms で遊んだことがありますが、いくつかのフィールドを非表示にして複雑な検証を行いたいと考えています。私が探しているコントロールのレベルは、フォームセットを必要とするか、手動でコーディングされた面倒なテンプレート ページを使用してすべてを手動で行う必要があるようですが、これは回避しようとしています。

私が見逃している素敵な機能はありますか?誰かがフォームセットを使用するための良い参照または例を持っていますか? 私は彼らの API ドキュメントに週末を費やしましたが、まだわかりません。すべてを分解して手作業でコーディングすると、設計上の問題になりますか?

4

7 に答える 7

92

これは、 ModelFormsで実装するのはそれほど難しくありません。フォーム A、B、および C があるとします。各フォームとページを印刷し、POST を処理する必要があります。

if request.POST():
    a_valid = formA.is_valid()
    b_valid = formB.is_valid()
    c_valid = formC.is_valid()
    # we do this since 'and' short circuits and we want to check to whole page for form errors
    if a_valid and b_valid and c_valid:
        a = formA.save()
        b = formB.save(commit=False)
        c = formC.save(commit=False)
        b.foreignkeytoA = a
        b.save()
        c.foreignkeytoB = b
        c.save()

カスタム検証のドキュメントは次のとおりです

于 2009-02-22T16:09:05.280 に答える
69

私はちょうど 1 日前にほぼ同じ状況にありました。これが私の 2 セントです。

1) 私は間違いなく、ここで単一のフォームでの複数のモデルエントリの最短かつ最も簡潔なデモを見つけました: http://collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/ .

簡単に言うと、モデルごとにフォームを作成し、keyarg を<form>使用して単一のテンプレートに両方を送信し、ビューで検証を処理します。prefix依存関係がある場合は、依存関係の前に「親」モデルを保存し、「子」モデルの保存をコミットする前に外部キーに親の ID を使用してください。リンクにはデモがあります。

2)おそらくフォームセットはこれを行うのに打ち負かされる可能性がありますが、私が掘り下げた限り、フォームセットは主に同じモデルの倍数を入力するためのものであり、オプションで外部キーによって別のモデルに関連付けることができます. ただし、複数のモデルのデータを入力するためのデフォルトのオプションはないようであり、それはフォームセットの目的ではないようです。

于 2009-06-12T09:50:28.660 に答える
27

私はごく最近、いくつかの問題を抱えていて、これを行う方法を見つけました。Primary、B、Cの3つのクラスがあり、B、Cにはプライマリへの外部キーがあると仮定します

    class PrimaryForm(ModelForm):
        class Meta:
            model = Primary

    class BForm(ModelForm):
        class Meta:
            model = B
            exclude = ('primary',)

    class CForm(ModelForm):
         class Meta:
            model = C
            exclude = ('primary',)

    def generateView(request):
        if request.method == 'POST': # If the form has been submitted...
            primary_form = PrimaryForm(request.POST, prefix = "primary")
            b_form = BForm(request.POST, prefix = "b")
            c_form = CForm(request.POST, prefix = "c")
            if primary_form.is_valid() and b_form.is_valid() and c_form.is_valid(): # All validation rules pass
                    print "all validation passed"
                    primary = primary_form.save()
                    b_form.cleaned_data["primary"] = primary
                    b = b_form.save()
                    c_form.cleaned_data["primary"] = primary
                    c = c_form.save()
                    return HttpResponseRedirect("/viewer/%s/" % (primary.name))
            else:
                    print "failed"

        else:
            primary_form = PrimaryForm(prefix = "primary")
            b_form = BForm(prefix = "b")
            c_form = Form(prefix = "c")
     return render_to_response('multi_model.html', {
     'primary_form': primary_form,
     'b_form': b_form,
     'c_form': c_form,
      })

このメソッドを使用すると、必要な検証をすべて実行できるだけでなく、3 つのオブジェクトすべてを同じページに生成することもできます。また、JavaScript と隠しフィールドを使用して、同じページに複数の B、C オブジェクトを生成できるようにしました。

于 2009-03-03T13:05:53.570 に答える
11

からのMultiModelFormは、 Gnudiff の回答django-betterformsで説明されていることを行うための便利なラッパーです。通常の s を単一のフォームとして透過的に (少なくとも基本的な使用法では) 使用される単一のクラスにラップします。以下のドキュメントから例をコピーしました。ModelForm

# forms.py
from django import forms
from django.contrib.auth import get_user_model
from betterforms.multiform import MultiModelForm
from .models import UserProfile

User = get_user_model()

class UserEditForm(forms.ModelForm):
    class Meta:
        fields = ('email',)

class UserProfileForm(forms.ModelForm):
    class Meta:
        fields = ('favorite_color',)

class UserEditMultiForm(MultiModelForm):
    form_classes = {
        'user': UserEditForm,
        'profile': UserProfileForm,
    }

# views.py
from django.views.generic import UpdateView
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import redirect
from django.contrib.auth import get_user_model
from .forms import UserEditMultiForm

User = get_user_model()

class UserSignupView(UpdateView):
    model = User
    form_class = UserEditMultiForm
    success_url = reverse_lazy('home')

    def get_form_kwargs(self):
        kwargs = super(UserSignupView, self).get_form_kwargs()
        kwargs.update(instance={
            'user': self.object,
            'profile': self.object.profile,
        })
        return kwargs
于 2015-10-19T12:05:43.293 に答える
5

現在、機能する回避策があります(単体テストに合格しています)。他のモデルから限られた数のフィールドのみを追加したい場合、これは私の意見では良い解決策です。

ここで何か不足していますか?

class UserProfileForm(ModelForm):
    def __init__(self, instance=None, *args, **kwargs):
        # Add these fields from the user object
        _fields = ('first_name', 'last_name', 'email',)
        # Retrieve initial (current) data from the user object
        _initial = model_to_dict(instance.user, _fields) if instance is not None else {}
        # Pass the initial data to the base
        super(UserProfileForm, self).__init__(initial=_initial, instance=instance, *args, **kwargs)
        # Retrieve the fields from the user model and update the fields with it
        self.fields.update(fields_for_model(User, _fields))

    class Meta:
        model = UserProfile
        exclude = ('user',)

    def save(self, *args, **kwargs):
        u = self.instance.user
        u.first_name = self.cleaned_data['first_name']
        u.last_name = self.cleaned_data['last_name']
        u.email = self.cleaned_data['email']
        u.save()
        profile = super(UserProfileForm, self).save(*args,**kwargs)
        return profile
于 2012-04-18T20:53:18.140 に答える
3

「いくつかのフィールドを非表示にして、複雑な検証を行いたい。」

組み込みの管理インターフェイスから始めます。

  1. 目的のフィールドを表示する ModelForm を構築します。

  2. フォーム内の検証ルールを使用してフォームを拡張します。通常、これはcleanメソッドです。

    この部分が適切に機能することを確認してください。

これが完了したら、組み込みの管理インターフェイスから離れることができます。

次に、1 つの Web ページで部分的に関連する複数のフォームをいじることができます。これは、すべてのフォームを 1 ページに表示するための一連のテンプレートです。

次に、ビュー関数を記述して、さまざまなフォームのものを読み取って検証し、さまざまなオブジェクトの save() を実行する必要があります。

「分解してすべてをハンドコーディングするとしたら、それは設計上の問題ですか?」いいえ、あまりメリットがないのに時間がかかります。

于 2009-02-20T14:38:37.510 に答える
2

Django のドキュメントによると、インライン フォームセットはこの目的のためのものです。

https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsetsを参照してください

于 2012-05-26T00:16:10.387 に答える