web-dev-qa-db-ja.com

インラインフォームセットを使用したモデルと関連モデルの作成

[ Django users | Google Groups にも投稿しています。]

inline formset docs の例を使用すると、edit特定のモデルに属するオブジェクト(modelformsを使用)。インラインフォームセットを使用してcreating新しいオブジェクトに対して同じパターンに従うようにしてきましたが、この目的のための実用的な見解を引き出すのに十分に私の頭をクリアすることができません。

上記のリンクと同じ例を使用して、「Author」モデルとそれに関連する「Book」オブジェクトの新しいインスタンスをどのように作成しますか?

43
chefsmart

まず、Authorモデルフォームを作成します。

author_form = AuthorModelForm()

次に、ダミーの作者オブジェクトを作成します。

author = Author()

次に、次のようにダミーの作成者を使用してインラインフォームセットを作成します。

formset = BookFormSet(instance=author)  #since author is empty, this formset will just be empty forms

それをテンプレートに送ります。データがビューに返されたら、作成者を作成します。

author = AuthorModelForm(request.POST)
created_author = author.save()  # in practice make sure it's valid first

次に、インラインフォームセットを新しく作成した作成者にフックして保存します。

formset = BookFormSet(request.POST, instance=created_author)
formset.save()   #again, make sure it's valid first

編集:

新しいフォームにチェックボックスを表示しないようにするには、これをテンプレートにします。

{% for form in formset.forms %}
    <table>
    {% for field in form %}
        <tr><th>{{field.label_tag}}</th><td>{{field}}{{field.errors}}</td></tr>
    {% endfor %}

    {% if form.pk %} {# empty forms do not have a pk #}
         <tr><th>Delete?</th><td>{{field.DELETE}}</td></tr>
    {% endif %}
    </table>
{% endfor %}
38
priestc

私は実際にnbv4のソリューションに小さな調整を提案したいと思います:

If-elseステートメントの外で空のcreated_authorを作成せず、author_form.is_valid()内にフォームセットをネストして、author_formが有効でない場合(つまり、created_authorがインスタンス化されていない場合)のランタイムエラーを回避するとします。

の代わりに:

if request.method == 'POST':
    author_form = AuthorModelForm(request.POST)
    if author_form.is_valid():
        created_author = author_form.save()
        formset = BookFormSet(request.POST, instance=created_author)
        if formset.is_valid():
            formset.save()
            return HttpResponseRedirect(...)
else:
    ...

以下をせよ:

if request.method == 'POST':
    author_form = AuthorModelForm(request.POST)
    if author_form.is_valid():
        created_author = author_form.save(commit=False)
        formset = BookFormSet(request.POST, instance=created_author)
        if formset.is_valid():
            created_author.save()
            formset.save()
            return HttpResponseRedirect(...)
else:
    ...

このバージョンは、book_formsetが検証する機会が得られるまで、created_authorのコミットを回避します。修正するユースケースは、誰かが有効なAuthorFormに無効なBookFormSetを入力して再送信し続け、書籍が関連付けられていない複数のAuthorレコードを作成することです。これは私のプロジェクトトラッカーアプリで機能するようです( "Author"を "Project"に、 "Book"を "Role"に置き換えてください)。

37
MikeRand

models.py(連絡先)

class Contact(models.Model)
    first = models.CharField(max_length=30)
    middle = models.CharField('M.I.',max_length=30, blank=True)
    last = models.CharField(max_length=30)
    sort_order = models.PositiveIntegerField(default=99)

models.py(リンク)

class Link(models.Model):
    contact = models.ForeignKey(Contact)
    link = models.URLField()
    description = models.CharField(max_length=30)
    access_date = models.DateField(blank=True,null=True)

forms.py

from Django.forms import ModelForm
from contacts.models import Contact

class ContactAjaxForm(ModelForm):
    class Meta:
        model=Contact

views.py

def edit(request,object_id=False):
    LinkFormSet = inlineformset_factory(Contact, Link, extra=1)
    if object_id:
        contact=Contact.objects.get(pk=object_id)
    else:
        contact=Contact()
    if request.method == 'POST':
        f=forms.ContactAjaxForm(request.POST, request.FILES, instance=contact)
        fs = LinkFormSet(request.POST,instance=contact)
        if fs.is_valid() and f.is_valid():
            f.save()
            fs.save()
            return HttpResponse('success')
    else:
        f  = forms.ContactAjaxForm(instance=contact)
        fs = LinkFormSet(instance=contact)
    return render_to_response(
        'contacts/edit.html', 
        {'fs': fs, 'f': f, 'contact': contact}
    )

これは本の例に基づいているのではなく、私のサイトのコードから編集されています。私はそれをテストしていないので、いくつかのバグがあるかもしれませんが、全体的にはしっかりしているはずです。 Contactの空のインスタンスを使用することは推奨される方法ではありませんが、ロジックを少し節約して機能します。

編集:リンクモデルを追加し、ジェネリック外部キーではなく通常の外部キーに切り替えて混乱を招く

9
Ogre Codes