Pocket

こんにちは、渡邉です。
入社後初の本ブログヘの投稿です。
これからも末永くよろしくお願いします。

昨今では科学計算や機械学習をメインに利用が目立つPythonですが、PythonはWebアプリケーションを構築するフレームワークが多数存在し、今後はWebアプリケーション開発でも利用が想定出来ます。
そこで今回、PythonでWebアプリケーションの構築を行おうと思います。
Pythonで作れば、Matplitlibなど機械学習や関連するライブラリが利用でき、その結果をWeb上で表示することも出来るでしょう。

今回は下記の内容で進めます。

  • 作成するサンプルアプリケーション
  • 環境作成
  • コード生成とその内容
  • 画面遷移(ルーティング)
  • テンプレート
  • フォームの送信と受信

では順を追って説明します。

作成するサンプルアプリケーション

昨今はSPA(Single Page Application)が主流ではありますが、今回はサーバーサイドのフレームワークの説明なので、旧来からあるサーバーサイドレンダリングを行う(HTMLを返却する)アプリケーションをDjangoを用いて作成します。

具体的な画面遷移は下記の通りです。

入力ページと、その入力内容を受け取って出力を行なう出力ページの2ページを作成します。
入力ページでは日付を入力し、出力ページではその内容を受け取って入力された日付の曜日を出力します。

環境作成

Python3.6上にDjangoを追加します。
今回はpip(Python用のパッケージ管理システム)でライブラリを追加しますが、AnacondaであればAnaconda Navigatorから追加するのが良いでしょう。

pip install django

依存関係のあるライブラリをpipがダウンロードし、Djangoインストールにも成功すると、以下のようになります。

Collecting django
  Downloading Django-2.0.2-py3-none-any.whl (7.1MB)
    100% |████████████████████████████████| 7.1
Collecting pytz (from django)
  Downloading pytz-2018.3-py2.py3-none-any.whl (509kB)
    100% |████████████████████████████████| 512
Installing collected packages: pytz, django
Successfully installed django-2.0.2 pytz-2018.3

動作確認をします。
PythonをREPLで起動し、PythonプロンプトからDjangoをインポートしてバージョンを表示させます。

# python
Python 3.6.4 |Anaconda, Inc.| (default, Jan 16 2018, 10:21:59) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> print(django.get_version())
2.0.2

pipコマンドでインストールしたバージョン “2.0.2” が表示されたので正常に動作していることが分かります。

確認が出来たのでREPLを exit() で終了します。

>>> exit()

さあ、Djangoでの開発を始める準備が整いました。

コード生成とその内容

PythonでのWebアプリケーション開発は django-admin コマンドから始めます。
django-admin コマンドは、プロジェクトの雛形コードの生成などを行ないます。
試しに django-admin コマンドを実行しましょう。

# django-admin

Type 'django-admin help ' for help on a specific subcommand.
    
Available subcommands:
    
[django]
    check
    compilemessages
    createcachetable
    dbshell
    diffsettings
    dumpdata
    flush
    inspectdb
    loaddata
    makemessages
    makemigrations
    migrate
    runserver
    sendtestemail
    shell
    showmigrations
    sqlflush
    sqlmigrate
    sqlsequencereset
    squashmigrations
    startapp
    startproject
    test
    testserver
Note that only Django core commands are listed as settings are not properly configured (error: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.).

django-adminに続いてサブコマンドを指定することで、様々なことが行えることが分かると思います。

さて、それではコードを置きたい場所に cd で移動した後、プロジェクトの雛形コードの生成を行なう startproject サブコマンドを実行します。
startprojectサブコマンドの後にプロジェクト名が必要ですので、今回は sample_prj とします。

# django-admin startproject sample_prj

何も表示されずコマンドは終了しますが正常終了しています。
sample_prjというディレクトリが作成され、このようなディレクトリとファイルが作成されます。

sample_prj
│  manage.py
│
└─sample_prj
        settings.py
        urls.py
        wsgi.py
        __init__.py

外側のsample_prjディレクトリは入れ物のディレクトリです。後から名前を変更しても構いません。
manage.pyはプロジェクトに様々な操作をするためのユーティリティです。
内側のsample_prjディレクトリはPythonパッケージです。パッケージ名ですので、後から変更すると影響が大きいので変更はおすすめしません。
__init__.pyはPythonにこのディレクトリがパッケージであることを知らせるコードです。
settings.pyは設定に利用するコードです。例えばデータベースの接続先の定義に利用します。
urls.pyはリクエストURLと実行する処理を紐付けるコードです。
wsgi.pyはWSGI互換Webサーバーとのエントリーポイントです。

今はsample_prjの一階層上にいると思うので、外側のsample_prjディレクトリに移動します。

cd sample_prj

続いてmanage.pyを使って組み込みサーバーを起動して、自動生成したコードが動作するか試します。

# python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).

You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions
Run 'python manage.py migrate' to apply them.
February 15, 2018 - 23:58:28
Django version 2.0.2, using settings 'sample_prj.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

http://127.0.0.1:8000/ で起動出来たので、ブラウザでアクセスしましょう。

このような画面が表示されれば、起動確認はOKです。

続いてアプリケーションを作成します。
アプリケーションの名前は sample_app とします。
外側のsample_prjディレクトリでmanage.pyを使ってアプリケーションを作成します。

# python manage.py startapp sample_app

sample_appというディレクトリが作成され、sample_appディレクトリにはこのようなディレクトリとファイルが作成されます。

├─sample_app
│  │  admin.py
│  │  apps.py
│  │  models.py
│  │  tests.py
│  │  views.py
│  │  __init__.py
│  │
│  └─migrations
│          __init__.py

sample_appをプロジェクトに登録します。
内側のsample_prjディレクトリにあるsettings.pyを開くと、INSTALLED_APPSの記述があります。
ここにsample_appの項目を追記します。

INSTALLED_APPS = [
    'sample_app.apps.SampleAppConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

画面遷移(ルーティング)

リクエストURLと実行する処理を紐付ける(ルーティングする)には、urls.pyを編集します。
urls.pyはプロジェクトで設定するものとアプリケーションで設定するものの2つが必要です。
プロジェクトで設定するurls.pyはすでに自動生成されているのでそれを編集し、アプリケーションで設定するurls.pyは自動生成されないので自分で作成する必要があります。

以降は http://127.0.0.1:8000/sample_app/input というURLのアクセスを処理するコードになります。

まずプロジェクトのurls.pyにアプリケーションへ誘導するコードを追記します。
元のコードは下記の通りです。

from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

これを下記のようにします。

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('sample_app/', include('sample_app.urls')),
    path('admin/', admin.site.urls),
]

includeのimportを追加し、urlpatternsにsample_appへ来たリクエストを後述するsample_app.urlsへ飛ばす行を追加します。

続いてアプリケーションのurls.pyを作成します。
sample_appディレクトリにurls.pyファイルを作成し、下記のようなコードを記述します。

from django.urls import path

from . import views

urlpatterns = [
    path('input', views.input),
]

input に来たリクエストを views.input 関数に飛ばしていますので、sample_appディレクトリのviews.pyを下記のように記述します。

from django.http import HttpResponse

def input(request):
    return HttpResponse("Hello world.")

ここまでの記述が、http://127.0.0.1:8000/sample_app/input の sample_app をプロジェクトのurls.pyがルーティングし、input をアプリケーションのurls.pyがルーティングし、最後にアプリケーションのviews.pyが “Hello world.” の文字列をブラウザに返す処理です。

python manage.py runserver でサーバーを起動し、ブラウザで http://127.0.0.1:8000/sample_app/input にアクセスしてみましょう。
下記のようなページが表示されれば成功です。

テンプレート

先程は “Hello world.” という文字列をブラウザに返しました。
ですが返したいのはHTMLです。
HttpResponse()にHTMLを記述することは可能ですが、テンプレートとなるHTMLを読み込みそれをブラウザに返却するのが一般的です。

そのための変更をアプリケーションのviews.pyに追記します。

from django.http import HttpResponse
from django.template import loader

def input(request):
    template = loader.get_template("sample_app/input.html")
    return HttpResponse(template.render({}, request))

まずloader.get_template関数でテンプレートのHTMLを読み込みます。
次にテンプレートの置換部分を処理するパラメータを渡しますが、今回表示する入力画面はパラメータを必要としないので、空の配列を渡しています。

続いてテンプレートとなるファイルを作成します。
ファイルは sample_app/templates/sample_app/input.html です。

<html>
<body>
    <form method="post" action="output">
        {% csrf_token %}
        <input type="text" name="date">
        <input type="submit">
    </form>
</body>
</html>

{% csrf_token %}はCSRF対策で入れないとならない項目です。
テキスト入力と送信ボタンをそれぞれひとつ配置したページです。
ここまでの記述で、http://127.0.0.1:8000/sample_app/input にアクセスすると、下記のようなページが表示されると思います。

フォームの送信と受信

日付の入力ページが出来たので、次に入力ページの送信内容を受け取って曜日を返却する出力ページを作ります。
まずはアプリケーションのurls.pyに出力ページのルーティングを追記します。

from django.urls import path

from . import views

urlpatterns = [
    path('input', views.input),
    path('output', views.output),
]

outputのURLをviews.output関数にルーティングするよう記述しました。
続いてsample_appディレクトリのviews.pyにviews.output関数を追加します。

from django.http import HttpResponse
from django.template import loader
from datetime import datetime as dt

def input(request):
    template = loader.get_template("sample_app/input.html")
    return HttpResponse(template.render({}, request))

def output(request):
    weekdays = ["月","火","水","木","金","土","日"]
    input_date = request.POST["date"]
    date_value = dt.strptime(input_date, "%Y-%m-%d")
    weekday_value = weekdays[date_value.weekday()]

    template = loader.get_template("sample_app/output.html")
    context = {
        "input_date": input_date,
        "weekday": weekday_value,
    }
    return HttpResponse(template.render(context, request))

weekdaysはあとに出てくる日付関数weekday()の値に応じた日本語を返すための配列です。
input_date = request.POST[“date”]はPOSTされた文字列値を取得しています。
date_value = dt.strptime(input_date, “%Y-%m-%d”)はPOSTされた文字列値を日付型に変換します。”%Y-%m-%d”とある通り、年月日をハイフンで区切った文字列を想定しています。
weekday_value = weekdays[date_value.weekday()]は日付関数weekday()の値に応じた日本語を取得します。
ここまでの結果をcontextに詰めて、テンプレートに渡します。
テンプレートのinput_dateとweekdayがここの値で置き換わります。

最後にテンプレートとなるファイルを作成します。
ファイルは sample_app/templates/sample_app/output.html です。

<html>
<body>
    {{ input_date }}は、{{ weekday }}曜日です。
</body>
</html>

実行してみましょう。
まずブラウザでhttp://127.0.0.1:8000/sample_app/input にアクセスし、入力欄に「2018-01-01」と入兎力します。

送信ボタンをクリックして出力ページに遷移します。

うまく動作したと思います。

いかがでしょうか?
Djangoを試してみたくなりましたか?