Django基礎(チャットボットをWebアプリにするための準備)

今回の位置づけ

前回の復習

  • チャットボット=自動応答するプログラム(チャットボットの概要
  • ライブラリ chatterbot を使ったPythonスクリプトを動かした(デモ)
my_chatbot.py
 1from chatterbot import ChatBot
 2from chatterbot.languages import JPN
 3from chatterbot.trainers import ChatterBotCorpusTrainer
 4
 5
 6class CustomJPN(JPN):
 7    ISO_639_1 = "ja_core_news_sm"
 8
 9
10if __name__ == "__main__":
11    chatbot = ChatBot("Training from corpus bot", tagger_language=CustomJPN)
12
13    trainer = ChatterBotCorpusTrainer(chatbot)
14    trainer.train("chatterbot.corpus.japanese")
15
16    while True:
17        try:
18            user_input = input("You: ")
19            response = chatbot.get_response(user_input)
20            print(f"Bot: {response}")
21        except (KeyboardInterrupt, EOFError, SystemExit):
22            break

今回やること

チャットボットをWebアプリとして動かすための 準備 をします。

  • Djangoを使って手元のPCで動くアプリケーションを開発していきます(デモ)
  • 今回チャットボットは触りません

DjangoによるWebアプリ

アンケート:Djangoを

  1. 授業を元に自分でアプリ作った
  2. これまでの授業で受けた
  3. 今回はじめて

埋め込みではなく、手元で見たい場合のリンク:https://ftnext.github.io/2020_slides/pycon_shizu_Feb_django_intro/slide.html

※この資料はWebアプリ開発が初めての方向けに説明しているので、知っているところは飛ばしてください

Webアプリ

詳しくは、登壇資料のスライド9〜27

  • WebアプリはWebブラウザから使うアプリ
  • Webアプリケーションフレームワーク(以下、フレームワーク)を使って作る
  • 開発者は フレームワークの流儀に従って コードを追加する
  • Djangoはフレームワークの1つ

Djangoの流儀

ファイルの配置

  • 決められたルールに従ってファイルを配置する
  • Djangoが用意しているコマンド を使う

ファイル配置の単位(このあと説明します)

  • プロジェクト
  • アプリケーション

Djangoの流儀に従ってPythonを書く

  • URL設定
  • ビュー
  • テンプレート

対応する ファイル (PythonやHTML)があります(このあと説明します)

プロジェクト/アプリケーション作成

Djangoのインストール

ChatterBot をインストールした仮想環境を有効にします。 これまでにPython 3.7系で仮想環境を作っています(環境構築)。

$ cd ~/programming/chatbot
$ source env/bin/activate
$ pip install 'Django<4'

インストールしたことの確認

$ django-admin --version
3.2.9

脱線:Djangoのバージョンについて

https://www.djangoproject.com/download/ のSupported Versions

LTS=long-term support(長期サポート)

  • 2系のLTS(2.2.x)はサポートが2022年4月まで
  • 3系のLTS(3.2.x)が登場しているので、 DjangoでWebアプリを新規に作るなら3.2.x がオススメ

8ヶ月おきに新しいバージョンが出ます(現在最新は3.2 → 4.0 → 4.1 → ...)

Djangoの用語:プロジェクトとアプリケーション

登壇資料のスライド31〜36

以下は、Djangoの用語としての意味です

プロジェクト

  • Djangoで作るWebアプリ全体の構成
  • ディレクトリとその中に置かれるファイルを指す
  • Webアプリに プロジェクトは1つ

アプリケーション

  • Webアプリの機能1つ1つ
  • ディレクトリとその中に置かれるファイルを指す(プロジェクトとは置かれるファイルが異なります)
  • Webアプリは 1つ以上のアプリケーション からなる
    • チャットボットと会話する機能のアプリケーション
    • ユーザ管理(ログイン・ログアウトなど)機能のアプリケーション

配置イメージ

├── プロジェクト
├── アプリケーションA
├── アプリケーションB
├──  :

プロジェクト作成と初期設定

プロジェクト作成

djangochatbot という名前のプロジェクトを作ります。

$ django-admin startproject djangochatbot

ls で確認すると以下のディレクトリ構造になっていることが確認できます。

~/programming/chatbot
├── djangochatbot  # <- このあと中を見ます
├── db.sqlite3  # <- これまでに実行した python my_chatbot.py でできた
├── env
├── greetings_ja.yml
└── my_chatbot.py
djangochatbot
├── djangochatbot  # <- プロジェクト
└── manage.py  # <- プロジェクト作成で作られます

~/programming/chatbot 直下の djangochatbot ディレクトリをリネームしましょう。 Webアプリのソースコードが置かれるので app とします(プロジェクトのディレクトリと名前を変えることで説明しやすくなる都合もあります)。

$ mv djangochatbot app

Djangoアプリのサーバを動かす

以降は app ディレクトリで作業します。

$ cd app

プロジェクト作成時にできた manage.py はDjangoでのアプリケーション開発がしやすくなるサブコマンドを提供します。 runserver サブコマンドで、Djangoアプリのサーバが起動します。

$ python manage.py runserver

http://127.0.0.1:8000/ をブラウザで開き、ロケットが動いている画面が見えたら、サーバは問題なく動いています!

注釈

Djangoアプリのサーバの停止は Control-C です。

Tip

シェルを複数開き、1つで python manage.py runserver しておくと開発しやすいです。 Djangoアプリのサーバはファイルの変更を検知して自動で読み込み直します。 ただし新規追加したファイルは読み込めない場合があるので、ファイルを新規追加したときは サーバを止めて再度 runserver するのをオススメします。

settings.py を変更

警告

手元のPC(=ローカル環境)で動かすのを優先してプロジェクトを設定しています。 Webアプリとして公開するには settings.pySECRET_KEYSTATIC_ROOT などの追加設定が必要です。

日本語の設定に変更します。 settings.py には変数が定義されていて、指す値を変えることで設定を変更できます。

以下の2つの変数を探して、指す値を変更します。

  • LANGUAGE_CODE
  • TIME_ZONE
変更前
app/djangochatbot/settings.py
LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'
変更後
app/djangochatbot/settings.py
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

日本語・JSTに設定しました。

http://127.0.0.1:8000/ をブラウザで開くと、英語だった表示が日本語に変わっています。

アプリケーション作成とそれに伴う設定

アプリケーション作成

chat という名前のアプリケーションを作ります。 manage.pystartapp サブコマンドを使います。

$ python manage.py startapp chat

ls で確認しましょう。

app
├── chat  # <- アプリケーション
├── djangochatbot
└── manage.py

settings.py を変更

変数 INSTALLED_APPS を探して、指す値を変更します。 これはリストを指していて、リストの要素は文字列です。

作った chat アプリケーションをリストに追加します。

app/djangochatbot/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    "chat.apps.ChatConfig",
]
発展:追加した文字列の意味

chat アプリケーションの一部として作られた app/chat/apps.py の中のクラスを指定しています。

app/chat/apps.py
from django.apps import AppConfig


class ChatConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'chat'

HTMLを表示する

ブラウザで http://127.0.0.1:8000/ を開いたときに、いまはロケットのページが見えています。 これを、 私たちが用意したHTMLが表示される ように変更します。

HTMLを表示するためには

リクエストとレスポンス

登壇資料のスライド40〜47

  • リクエスト: URLやブラウザに入力したデータ をリクエストとしてWebアプリのサーバに送信
  • レスポンス:Webアプリは 処理結果(HTMLを含む) をレスポンスとして、Webブラウザに返す

Djangoの流儀に則った開発項目

HTMLの表示には、以下の要素が必要です。

  1. URL設定(アプリケーションのURL設定を追加)
  2. ビュー(関数を追加)
  3. テンプレートを追加
https://raw.githubusercontent.com/ftnext/2020_slides/master/docs/_images/spzcolab_Jan_django/2/8-urlconf_view_template.png

1つずつ見ていきましょう。

URL設定

URL設定は、リクエストのURLを元に、ビューにある処理を呼び出します(登壇資料のスライド49〜52)。

https://raw.githubusercontent.com/ftnext/2020_slides/master/docs/_images/pycon_shizu_Feb_django_intro/2/4-urlconf.png

今回の作り方では、プロジェクトの settings.py にて、プロジェクトの urls.py が使われるように設定されています。

プロジェクトの urls.py

変更前
app/djangochatbot/urls.py
from django.contrib import admin
from django.urls import path

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

ブラウザで http://127.0.0.1:8000/admin/ を開くと、Djangoが用意している管理画面にログインするための画面が表示されます。

URL設定の仕組み

URL(例:http://127.0.0.1:8000/admin/ )は3つに分かれます(登壇資料のスライド114)。

  • プロトコル http
  • ホスト 127.0.0.1:8000 (=手元のPCの8000番ポート)
  • パス admin/

URL設定は パス を見ます。

app/djangochatbot/urls.py には「パスが "admin/" だったら、Djangoで用意している管理画面用のURL設定に沿って動作する」指定です。

注釈

ブラウザでは普段ドメイン名を入力しますよね(例:https://www.google.com/ ) DNSという仕組みでドメイン名からIPアドレスに変換されています

URL設定に追加する

ブラウザで http://127.0.0.1:8000/ を開いたときの動きを設定したいので、パスは "" (空文字列)です。

以下のように設定します。

app/djangochatbot/urls.py
from django.contrib import admin
from django.urls import include, path

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

include のimportを追加します。 path("", include("chat.urls")) は、「パスが "admin/" でない場合、chatアプリケーションの urls.py にあるURL設定を使う」という指定です。

いまは app/chat/urs.py がないので python manage.py runserver はエラーを送出します(サーバは動いていません)。

注釈

今回作るチャットボットアプリは小さいですが、Djangoで一般的なプラクティスに沿って手順を書いています。 例えばURL設定で include を使わずに、プロジェクトの urls.py だけで進めることもできます。

Djangoで一般的なプラクティスに従うことで、今は小さなチャットボットアプリでも今後機能追加がしやすくなります。

アプリケーションの urls.py

app/chat/urs.py を作りましょう。

$ touch chat/urls.py
app/chat/urls.py
1from django.urls import path
2
3from chat import views
4
5app_name = "chat"
6
7urlpatterns = [
8    path("", views.home, name="home"),
9]

このURL設定は、「パスが "" (空文字列)のとき、chat/views.pyhome (関数)を呼び出す」としています。

chat/views.py はアプリケーション作成時にできていますが、中身は空なので、 views.home がないというエラー(AttributeError)が送出されます(まだサーバは動いていません)。

ヒント

5行目の app_name もDjangoで一般的なプラクティスの1つです。 複数のアプリケーションで同じ name のURL設定があったとしても、<app_name>:<name> として区別できます。

ビュー

ビューは、URL設定により呼び出され、リクエストを処理し、レスポンスを返します(登壇資料のスライド54〜58)。 実体は関数です(クラスで定義することもできますが、この講義では扱いません)。

chat/views.pyhome 関数を定義します。

app/chat/views.py
1from django.shortcuts import render
2
3
4def home(request):
5    return render(request, "chat/home.html")

URL設定により呼び出されるビューの関数は第1引数に request をとります(4行目)。 ここにはリクエストのデータが詰まっています。

home 関数は chat/home.html (テンプレート)を使ってレスポンスを組み立て、それを返しています(ブラウザに返ります)。

以上の設定で python manage.py runserver は動作するようになりました。

ブラウザで http://127.0.0.1:8000/ を開いてみましょう。 すると、 TemplateDoesNotExist (テンプレートが存在しない)と表示されます。

テンプレート

テンプレートは、Webアプリの見た目に関わります。 HTMLとDjango独自のタグで書かれます(登壇資料のスライド60〜66)。

今送出されているエラーは「テンプレートが存在しない」ですから、テンプレートを配置すれば解決します。 空のテンプレートを置きましょう。

空のテンプレートを置く

manage.py やプロジェクト、アプリケーションがあるディレクトリに templates という名前のディレクトリを作ります。 ここに今回のアプリで使うテンプレートを置いていきます。

ビューで chat/home.html というテンプレートを指定しているので、 chat ディレクトリの中に home.html を置きます。

$ mkdir -p templates/chat
$ touch templates/chat/home.html

settings.py を変更

templates ディレクトリにテンプレートがあるという設定を追加します。

変更するのは TEMPLATES です。 これはリストで、要素は辞書です。 キー "DIRS" の値([])を書き換えます。

変更後
app/djangochatbot/settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / "templates"],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

ヒント

BASE_DIRpathlibPath オブジェクトです(settings.py の上部で定義されています)。 Path オブジェクトは / 演算子で、新たなパスを作れます。

>>> from pathlib import Path
>>> Path("app")
PosixPath('app')
>>> Path("app") / "templates"
PosixPath('app/templates')

ブラウザで http://127.0.0.1:8000/ を開くと、真っ白な画面が表示されます。 エラーがなくなりました!

いま chat/home.html にはなにもHTMLを書いていないので、真っ白い画面が表示されます。 テンプレートにHTMLを書いてからブラウザをリロードすると反映されます(例:<h1>こんにちは</h1>)。

ヒント

templates ディレクトリを作るのもDjangoで一般的なプラクティスの1つです。 アプリケーションの中に chat/templates/chat/home.html を作るだけでもエラーは解決しますが、 アプリケーションが増えたときに templates ディレクトリにテンプレートがまとまっているというのは便利です。