ユーニックス総合研究所

  • home
  • archives
  • python-django-linebbs-set-form

Django入門: フォームを配置する ~ 簡単な一行掲示板アプリを作る その13【Windows10】

  • 作成日: 2020-10-24
  • 更新日: 2023-12-26
  • カテゴリ: Django

はじめに

この記事は「Djangoで一行掲示板を作ろう」という趣旨のシリーズの記事です。

前回までにDjangoのプロジェクトとアプリを作成し、ルート情報とビューを接続し、テンプレートを描画して、モデルを作りマイグレーションを行い、ビューでオブジェクトを取得し、管理サイトでオブジェクトを追加してテンプレートで表示して、フォームを作るというところまでやりました。

今回からDjangoのフォームを実際に配置していきたいと思います。

前提として開発環境のOSはWindows10, シェルはコマンドプロンプトです。
仮想環境を使っていますが、仮想環境については第一回の記事をご覧ください。
初期作業フォルダはプロジェクト内のmanage.pyのあるフォルダです。

ビューからコンテキストにフォームを保存

manage.pyのあるフォルダからbbs\views.pyを開きます。
これを次のように編集します。

from bbs.forms import PostForm  # <- これを追加  

まず、↑のように前回作成したPostFormをインポートします。

def home_view_get(request):  
    context = {}  

    context['title'] = '一行掲示板'  
    context['posts'] = Post.objects.all()  
    context['form'] = PostForm()  # <- これを追加  

    return render(request, 'bbs/home.html', context)  

それから↑のようにhome_view_get()を編集します。
追加したのは↓の行です。

    context['form'] = PostForm()  # <- これを追加  

コンテキストにformという変数を作り、そこにPostFormのオブジェクトを保存しています。
このformはテンプレートで利用することになります。

ここまでのコードの全文は↓のようになります。

from django.shortcuts import render  
from django.http import HttpResponse  
from bbs.models import Post  
from bbs.forms import PostForm  # <- これを追加  


def home_view(request):  
    # request.methodによって処理を分岐  
    if request.method == 'GET':  
        return home_view_get(request)  
    elif request.method == 'POST':  
        return home_view_post(request)  
    else:  
        return HttpResponse('invalid method', status=400)  


def home_view_get(request):  
    """  
    パス bbs/ の GET  
    """  
    context = {}  # コンテキストを作成  

    context['title'] = '一行掲示板'  # ページのタイトル  
    context['posts'] = Post.objects.all()  # Postのリストを取得  
    context['form'] = PostForm()  # <- これを追加  

    # renderにコンテキストを渡しテンプレートを描画  
    return render(request, 'bbs/home.html', context)  


def home_view_post(request):  
    """  
    パス bbs/ の POST  
    """  
    return HttpResponse('TODO')  # 後で実装  

編集した行は2行だけですが、これでビューの編集は終わりです。

テンプレートにフォームを配置

次にmanage.pyのあるフォルダからbbs\templates\bbs\home.htmlを開きます。
これを次のように編集します。

{% extends 'bbs/base.html' %}  

{% block content %}  
<h1>{{ title }}</h1>  

<form method="POST" action="{% url 'bbs_home' %}">  
  {% csrf_token %}  
  {{ form.as_p }}  
  <button type="submit">投稿する</button>  
</form>  

<ul>  
  {% for post in posts %}  
    <li>{{ post.id }}: {{ post.content }}</li>  
  {% endfor %}  
</ul>  
{% endblock %}  

追加したのは↓の部分です。

<form method="POST" action="{% url 'bbs_home' %}">  
  {% csrf_token %}  
  {{ form.as_p }}  
  <button type="submit">投稿する</button>  
</form>  

formタグのmethod属性にはフォームで使用するメソッドを指定します。
今回の場合は掲示板への投稿になるのでメソッドはPOSTです。

それからaction属性にはリクエスト先のパスを指定します。

action="{% url 'bbs_home' %}  

{% url %}にパスの名前を指定するとその名前が参照され、パスが出力されます。
↑ではbbs_homeを指定していますが、これはbbs\urls.py内で指定している名前です。
↓の部分のname='bbs_home'がそうです。

    path('', home_view, name='bbs_home'),  # ルートにhome_viewを指定  

bbs_homeを解決すると/bbs/というパスになります。
次に↓の部分ですが、

  {% csrf_token %}  

↑はフォーム内にCSRFトークンを配置しています。
CSRFトークンとは悪意のあるアタッカーによるCSRF攻撃を防ぐための仕組みです。
CSRFCSRFトークンの仕組みについては↓の記事をご覧ください。

Djangoではフォームからの送信についてはこのCSRFトークンを配置するのが普通になっています。
これはWebアプリのセキュリティを守るためです。
このCSRFトークンの仕組みがないと、Webアプリに脆弱性が生まれ、悪意のあるアタッカーにWebアプリを悪用される可能性が高くなってしまいます。
また、ビューでこのCSRFトークンの仕組みを無効化することは可能です。

次に↓の部分ですが、

  {{ form.as_p }}  

↑はフォームの部品(inputタグ)を出力しています。
as_pというのはformのメソッドまたは属性です。
テンプレートではメソッドの呼び出しにカッコをつけません。
このas_pというのはフォームの部品をpタグで囲って出力するというメソッドです。

次に↓の部分です。

  <button type="submit">投稿する</button>  

これは送信ボタンです。

フォームを表示

では開発用サーバーを起動して動作確認してみます。

> python manage.py runserver 0.0.0.0:8123  

特に問題が無ければ↓のように表示されると思います。

HTMLソースを見てみると↓のようなHTMLが出力されています。

<h1>一行掲示板</h1>  
<form method="POST" action="/bbs/">  
  <input type="hidden" name="csrfmiddlewaretoken" value="xxxx">  
  <p><label for="id_content">Content:</label> <input type="text" name="content" maxlength="140" required="" id="id_content"> <span class="helptext">掲示板のポスト内容</span></p>  
  <button type="submit">投稿する</button>  
</form>  
<ul>  

    <li>1: てすと1</li>  

    <li>2: てすと2</li>  

    <li>3: てすと3</li>  

</ul>  

CSRFトークンは↓のようにhiddeninputタグとして出力されています。
この値は環境によって変わります。

  <input type="hidden" name="csrfmiddlewaretoken" value="xxxx">  

form.as_pで出力されたタグは↓のように出力されています。

  <p><label for="id_content">Content:</label> <input type="text" name="content" maxlength="140" required="" id="id_content"> <span class="helptext">掲示板のポスト内容</span></p>  

↑を見るとPostモデルのcontentフィールドのmax_lengthがそのままinputタグのmaxlengthに流用されていることがわかります。

おわりに

今回はフォームを配置して出力する所までやってみました。
次回からビューのPOSTメソッドを実装して、実際に投稿できるようにしていきたいと思います。

🦝 < フォームを信じよ