This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 3 years have passed since last update.

[Day 15]簡単なトピック投稿画面の作成

Last updated at Posted at 2021-01-20

January 20, 2021
←前回:Day 14 DetailViewを使った詳細表示画面の作成

「Djangoを学びたい!」とのことでありましたら[Day 1]Djangoの開発環境から読むことをおすすめします。

はじめに

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

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

新しい画面を作成するのでまずはテンプレートを作りましょう。
作成ファイルの場所は、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’というコンテキストを受け取るために記述しているのですが、もう少し先で解説します。

ここで私は{% csrf_token %}に関しては理解できたのですが、{{form.as_p}}に関しては「???」になってしまいました。

フォームを使う

さて、ここでフォームというものが登場します。
フォームというと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/にアクセスしてみましょう。

image.png

おわりに

だんだんとQiitaに投稿することが慣れてきました。
初期は「どうやって投稿するんだろう?」「こんな記事を投稿しいていいのか?」などの不安がありましたが、慣れてきました。

とか言って、急にやめてしまうパターンもなくはないので今後どうなるかは、「神のみぞ知る」って感じですね。(何言ってんだよ)

それではまたまた

←前回:Day 14 管理画面と管理者の作成
→次回:Day 16 FormとModelForm

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up