似非プログラマのうんちく

「似非プログラマの覚え書き」出張版

巳年じゃないけど Python やろうぜ(その 6)

Hello ページを作る(続き)

前回までで、テンプレートを利用して Web ページを表示させることができましたが、まだ Web アプリっぽくないですよね。

もう少しそれっぽくするにはフォームとかあったらいいんじゃないでしょうかね。

フォームを作成する

今回はフォームを使って

  • http://localhost:8000/hello/ にアクセスしたら、名前を入力するフォームが表示されるようにする
  • 名前を入力して送信したら、それを表示専用のページに渡して表示させる。リダイレクト先は http://localhost:8000/hello/thanks/ とする(「名前を入力してくれてありがとう !」的な感じ)


まずはフォームを作ります。django_test\hello\forms.py を新たに作成し、以下の内容にします。

from django import forms


class NameForm(forms.Form):
    your_name = forms.CharField(label='Enter your name', max_length=20)

次にこのフォームを表示させるテンプレート django_test\hello\templates\hello\form.html を作ります。

<!doctype html>
<html>
  <head>
    <title>Name Entry</title>
  </head>
  <body>
    <form action="." method="post">
      {% csrf_token %}
      {{ form.as_p }}
      <p><input type="submit" value="送信"></p>
    </form>
  </body>
</html>

csrf_tokenCSRF(Closs-site Request Forgery)*1対策として入れておきます。

django_test\hello\views.py を編集します。

from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import NameForm


def hello(request):
    my_name = request.session['your_name']
    return render(request, 'hello/hello.html', {'my_name': my_name})


def get_name(request):
    if request.method == 'POST':
        form = NameForm(request.POST)
        if form.is_valid():
            your_name = form.cleaned_data['your_name']
            request.session['your_name'] = your_name
            return HttpResponseRedirect('thanks/')
    else:
        form = NameForm()
    return render(request, 'hello/form.html', {'form': form})

さりげなく indexhelloリファクタリングしておきます。入力された値に対しては is_valid() でデフォルトのバリデーションチェックを行っています。バリデーションチェックされたフォームの値から your_name の値を取り出してセッションに保存*2します。

最後に django_test\hello\urls.py を編集します。

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.get_name),
    url(r'^thanks/$', views.hello),
]
セッションを利用する

Django にはあらかじめセッションを管理するための仕組みが用意されています。

django_test\django_test\settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',  # これと
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'hello',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',  # これ!
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

これにより、Django はデータベースを利用してセッションの管理を行うことができます。そのためにはデータベースを利用する準備が必要です。

>manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying sessions.0001_initial... OK

これで db.sqlite3 (なければ作成されます)に django_sessions というテーブルが作成されます(その他にもいくつかテーブルができます)。

後はお約束通り、開発用サーバを起動して確認してみましょう。

試しに「Python」と入力して送信してみましょう。

なお、セッションの管理にデータベースではなくキャッシュサーバを使う方法もありますが、余力があればいずれ紹介します。

*1:ダミーサイトなどに情報を入力させ、それをもとにショッピングサイトの最終決済などの重要な処理を呼び出す、Web アプリケーションの脆弱性を利用した攻撃方法。これは、本来拒否すべきサイトからのリクエストを受け付けてしまうことで起こるので、対策としてトークンを埋め込むことにより、許可されたサイトからのリクエストであることを確認する方法が取られる。

*2:ページ遷移が発生するので、値はセッションに保存しないと消えてしまいます