1-14. 簡単なトピック投稿画面の作成する

今回のテーマは「簡単なトピック投稿画面の作成する」です。おまたせ致しました。ここまで時間が掛かりましたね。Django使っても全然Webアプリが出来上がらないじゃないかとお叱りを受けそうですが、何事も基礎が大事です。第一章でDjangoの使い方を大まかに捉えると応用は比較的簡単だと思います。

では掲示板の新規トピックを登録する画面を作っていきましょう。まずはフォームがあるだけのシンプルな登録画面を作ります。登録が完了するとTOP画面に作成したトピックが表示されるようにしましょう。

※本ページはDetailViewを使った詳細表示画面の作成まで読まれた方を対象としています。そのためサンプルソースコードが省略されている場合があります。

トピック登録画面のテンプレート作成

新しい画面を作成するのでまずはテンプレートを作りましょう。作成するファイルはtemplates/thread/create_topic.htmlです。

thread/create_topic.html



{% extends 'base/base.html' %}
{% block title %}トピック作成 - {{ block.super }}{% endblock %}
{% block content %}
<div class="ui grid stackable">
    <div class="eleven wide column">
        <div class="ui breadcrumb">
            <a href="{% url 'base:top' %}" class="section">TOP</a>
            <i class="right angle icon divider"></i>
            <a class="active section">トピック作成</a>
        </div>
        <div class="ui segment">
            <div class="content">
                <div class="header"><h3>トピック作成</h3></div>
                <form class="" action="{% url 'thread:create_topic' %}" method="POST">
                    {% csrf_token %}
                    {{form.as_p}}
                    <button type="submit" class="ui button">作成</button>
                </form>
            </div>
        </div>
    </div>
    {% include 'base/sidebar.html' %}
</div>
{% endblock %}

キーポイントが二つあります。1つは{% csrf_token %}ですね。これはクロスサイトリクエストフォージェリという脆弱性に対するセキュリティ対策でトークンによって認証されないリクエストは受け付けない仕組みです。POSTメソッドでは必須です。(意図的csrf_tokenなしでアクセスすることもできますが、セキュリティ上の脆弱性を熟考の上判断して下さい。)

もう一つは{{form.as_p}}ですね。これはビュー側から’form’というコンテキストを受け取るために記述しているのですが、もう少し先で解説します。

フォームを使う

さて、ここでフォームというものが登場します。フォームというとHTMLの入力フォームを思い浮かべると思いますが、Djangoにおけるフォーム機能はもう少し幅の広い機能を提供します。ウェブアプリがフォームを持つ場合、以下のような処理が必要にあります。

  • データをレンダリングするための準備
  • HTMLとしてフォームをレンダリングすること
  • フォームから送信されたデータを処理すること

Djangoではフォームというパーツがこれらの処理を守備範囲として受け持ちます。詳細は公式ドキュメントも参照下さい。

フォームにはついては別の機会にもう少し詳しく扱う予定ですが、ここではとにかく使ってみましょう。今回はModelFormというフォームを使います。まず、thread/forms.pyを作成します。

thread/forms.py


from django.forms import ModelForm
from . models import Topic

class TopicCreateForm(ModelForm):
    class Meta:
        model=Topic
        fields=[
            'title',
            'user_name',
            'category',
            'message',
        ]

ModelFormを継承したTopicCreateFormを用意します。ModelFormを継承したクラスはMetaクラスにmodelとfieldsを指定することでフォームを作成出来ます。今回のようにモデルに対応するフォームを作成する場合は便利な方法です。(今回は扱いませんが、ModelFormを使わずフォームを生成する方法も当然あります。)

ビューを作成する

次にthread/views.pyに関数ベースのビューを追加していきます。

thread/views.py


from django.shortcuts import render, redirect
from django.urls import reverse_lazy

from . forms import TopicCreateForm
from . models import Topic

def topic_create(request):
    template_name = 'thread/create_topic.html'
    ctx = {}
    if request.method == 'GET':
        ctx['form'] = TopicCreateForm()
        return render(request, template_name, ctx)
    
    if request.method == 'POST':
        topic_form = TopicCreateForm(request.POST)
        if topic_form.is_valid():
            topic_form.save()
            return redirect(reverse_lazy('base:top'))
        else:
            ctx['form'] = topic_form
            return render(request, template_name, ctx)

GETメソッドでアクセスされた場合とPOSTメソッドでアクセスされた場合に処理を分けています。とくに明示しない場合はGET
でのアクセスとして扱われます。TopicCreateFormのインスタンスをコンテキストで渡しています。これがthread/create_topic.htmlで描写されるというわけです。テンプレートの部分で説明を保留していましたが、先程フォームにはHTMLフォームとしてレンダリングする機能もあると説明しました。一番簡単なレンダリングは{{form}}とすることです。これは単順にHTMLのinputタグとlabelタグを並べるだけです。これをもう少し整形するための手法が以下の方法です

{{form.as_p}} : Pタグで囲んで段落毎に整形する。
{{form.as_ul}} : LIタグで囲んでリスト整形表示する。ただしULタグは別途記載する必要あり
{{form.as_table}}:テーブル表示するための整形。ただしTABLEタグは別途記載する必要あり

今回はform.as_pを使って整形したということです。もうお気づきかも知れませんが、as_p, as_ul, as_tableはそれぞれ整形されたHTMLタグを返す関数です。

POSTメソッドで受けた場合にはis_valid()関数を呼んでデータの精査を行います。今回はModelFormを使用しているためTopicモデルが有している情報に適しているか精査されます。文字の長さやNullの許容等が正しくない場合は精査に失敗します。正しいデータが来た場合はフォームのsave()関数を呼んで保存しています。この方法はModelFormの場合のみ使える方法です。ややこしいので別の機会に触れます。データの精査に失敗した場合はtopic_formにエラーメッセージが入っていますので、これをコンテキストとして渡して再度create_topic.htmlを表示します。

では、追加した関数とURLを結びつけるためにthread/urls.pyに追加していきます。

thread/urls.py


from django.urls import path

from . import views
app_name = 'thread'

urlpatterns = [
    path('create_topic/', views.topic_create, name='create_topic'),
]

これで準備は整いました。localhost:8080/thread/create_topic/にアクセスしてみましょう。

最後に

無事、トピックは登録出来ましたでしょうか?次回はDjangoにおけるフォームの役割についてもう少し見ていきたいと思います。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です