自動化無しに生活無し

WEBとかAIとかLinux関係をひたすら書く備忘録系ブログ

【Django】modelformset_factoryで1回のリクエストでまとめて投稿する【フォームセット】

thumbnail

1回のリクエストで、決まった個数のデータをまとめて投稿したい場合、modelformset_factory が有効。

ただし、状況によってはgetlistを使う方法のほうが有効の場合もあるので、よく考える必要がある。

modelformset_factory とは

例えば、1回のリクエストで5個のコメントをまとめて投稿する必要がある場合。

このようにフォームクラスを元に、フォームセットを作る。

from django import forms
from .models import Topic

class TopicForm(forms.ModelForm):
    class Meta:
        model	= Topic
        fields	= [ "comment" ]


from django.forms import modelformset_factory

TopicFormSet = modelformset_factory(Topic, form=TopicForm, extra=5)

ビューでこのフォームセットをコンテキストに渡す。

from django.shortcuts import render,redirect

from django.views import View
from .models import Topic

from .forms import TopicFormSet


class IndexView(View):

    def get(self, request, *args, **kwargs):

        context = {}
        context["topics"]   = Topic.objects.all()

        #                                     ↓これがないとこれまで投稿されたデータまで表示される。
        context["formset"]  = TopicFormSet(queryset=Topic.objects.none())

        return render(request,"bbs/index.html",context)

    def post(self, request, *args, **kwargs):

        formset = TopicFormSet(request.POST)

        if formset.is_valid():
            formset.save()
        else:
            print(formset)
            print(formset.errors)


        return redirect("bbs:index")

index   = IndexView.as_view()

この時、引数としてquerysetを与える。

postメソッドのバリデーション処理は、普通のフォームクラスのバリデーションと同じ。

テンプレート側でフォームセットを呼び出す。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>簡易掲示板</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>

    <main class="container">
        {# ここが投稿用フォーム #}
        <form method="post">
            {% csrf_token %}

            {{ formset.management_form }}
            {% for form in formset %}
                {{ form.as_p }}
            {% endfor %}
            <button type="submit">Save</button>
        </form>


        {# ここが投稿されたデータの表示領域 #}
        {% for topic in topics %}
        <div class="border">
            {{ topic.comment }}
        </div>
        {% endfor %}

    </main>
</body>
</html>

formsetには、Topic5個分のフォームが用意されている。それを全てレンダリングする。

結論

フォームテンプレートを使用しており、個数もサーバー側で取り決める必要があるため、やや汎用性に欠けると思った。

とはいえ、必ず一定個数を投稿したい場合には、getlistよりも厳重にできる。

関連記事

getlist と modelformset_factory の違い

https://noauto-nolife.com/post/django-multi-send/

  • 1回のリクエストで、必ず一定の個数を投稿したい場合: modelformset_factory
  • 1回のリクエストで、1個でも複数個でも投稿したい場合: getlist

とそれぞれ使い分けする方法が妥当と思われる。

ソースコード

https://github.com/seiya0723/startup_bbs_modelformset_factory

スポンサーリンク

シェアボタン

Twitter LINEで送る Facebook はてなブログ