FormView

FormViewはフォームを表示したり、フォームの送信を受け取ります。

今回は掲示板風なサイトを作成します。テーブルは以下のようにThreadとResponseからなり、ResponseのtitleはThreadのidと1対多の関係です。


入力画面は以下のようにThreadのタイトルとResponseのtextに対応した2つフォームをテンプレートに渡します。

モデル

test_app/models.py に今回は以下のように記述しました。

from django.db import models

# スレッド
class Thread(models.Model):
    title = models.CharField(verbose_name = 'スレッドタイトル', max_length=64)

    def __str__(self):
        return self.title

# スレッドへのレスポンス
class Response(models.Model):
    title = models.ForeignKey(Thread,on_delete=models.CASCADE, verbose_name = 'スレッドタイトル')
    text = models.TextField(verbose_name = 'テキスト')
    post_date = models.DateTimeField(verbose_name = '作成日', auto_now_add=True)

    def __str__(self):
        return self.text

View

FormViewを継承した「CreateThreadView」を作成しました。

from django.urls import reverse_lazy

# Create your views here.

from django.views.generic.edit import FormView
from .forms import CreateThreadForm, AddResponseForm
from .models import Thread

class CreateThreadView(FormView):
    template_name = "test_app/create_thread.html"
    model = Thread
    form_class = CreateThreadForm

    # テンプレートに渡すデータを作成
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # Formのインスタンスを取得
        add_response_form = AddResponseForm()
        create_thread_form = CreateThreadForm()

        # Formのインスタンスをreturn用の辞書に格納
        context = {
            "add_response_form" : add_response_form,
            "create_thread_form" : create_thread_form
        }
        return context

    # Formのチェック。問題がなければDBを更新
    def form_valid(self, form):

        # 引数ありのFormインスタンスを作成
        create_thread_form = CreateThreadForm(self.request.POST)

        # Formのチェック
        if create_thread_form.is_valid():

            # threadのインスタンスを作成して保存
            thread = create_thread_form.save()


        # 引数ありのFormインスタンスを作成
        add_response_form = AddResponseForm(self.request.POST)

        # Formのチェック
        if add_response_form.is_valid():

            # responseのインスタンスを作成。まだ保存しない
            response = add_response_form.save(commit=False)

            # threadに紐づいているIDを取得
            response.title_id = thread.id

            # 保存
            response.save()

        return super().form_valid(form)

    def get_success_url(self):
        return reverse_lazy("create_thread")

ポイントは「get_context_data」で2つのフォームをテンプレートに渡しています。

URL

まだ画面ひとつしか作成していないのでCreateThreadViewのみパスを通しています。

from django.urls import path
from .views import CreateThreadView
  
urlpatterns = [
    # /にアクセスした時、CreateThreadViewを呼び出す
    path("", CreateThreadView.as_view(), name="create_thread"),
]

テンプレート

最低限フォームを表示して、送信するだけですが、以下のようにしました。

<form method="post">
    {% csrf_token %}
    <div>スレッドタイトル (CreateThreadFormで作成) </div>
    <div>{{ create_thread_form.title }}</div><br>
    <div>最初のレス (AddResponseFormで作成) </div>
    <div>{{ add_response_form.text }}</div>
    
    <button type="submit">Submit</button>
</form>

ここまで行えば以下の画面が表示できると思います。

コメント

タイトルとURLをコピーしました