1. HOME
  2. ブログ
  3. IT技術
  4. 【第2回】Responderを使ってDjangoチュートリアルをやってみた【データベース・モデル構築編】

【第2回】Responderを使ってDjangoチュートリアルをやってみた【データベース・モデル構築編】

第2回~Responderを使ってDjangoチュートリアルをやってみた~

今回も、Responder(レスポンダー)を使って「Djangoのチュートリアル」をやってみたいと思います。

Responderで追う形になりますので、多少内容が異なる部分がありますが、成果物はできるだけ同じモノになるよう作る予定です。

今回は、Django のチュートリアル「はじめての Django アプリ作成、その2」をご参考下さい。

【はじめての Django アプリ作成、その2】
https://docs.djangoproject.com/ja/2.2/intro/tutorial02/

第1回はこちら

データベースの構築

Responder単体では、Djangoのように単体で簡単にデータベース作成はできません。

そこで、「SQLAlchemy(エスキューエルアルケミー)」と呼ばれる、Pythonでデータベース管理ができるライブラリの力を借りることにしました。

他にも、データベース管理のためのPythonライブラリはあるようですが、情報がたくさんあるSQLAlchemyを使うことにします。

データベースを構築

では、早速データベースを構築していきましょう!

今回は、SQLite3を使ってデータベースを構築していきます。

以下は、データベースの設定ファイル db.py です。

作成場所は、プロジェクトのルートで構いません。

現段階では、SQLAlchemyを触ったことのない人にとっては何が書いてあるか分からないかもしれません。

でも、今の段階では深く理解する必要はありません。

「ああ、SQLite3っていうデータベースを使うんだな」くらいに思っていただければOKです。

モデルの定義

今回、必要なテーブル(モデル)は、以下の通りとなります。

Question テーブルid(主キー)、question_text(質問事項)、pub_date(公開日時)
Choice テーブルid(主キー)、question(紐づけられた質問)、choice_text(選択肢テキスト)、votes(投票数)
User テーブルid(主キー)、username(ユーザ名)、password(ハッシュ化されたパスワード)

これらは、SQLAlchemyにおいてクラスで定義可能です。

models.py

これらのモデル定義をするために、 models.py を作成し、以下のように記述します。

コードを見てわかるように、各クラスのメンバ変数が各テーブルのレコードの要素となります。

このとき、各モデルのインスタンスを print() できるように def __str__() も実装しておきましょう!

実行してみよう!

さて、実際に models.py を実行してみてください。

db.sqlite3 というファイルが生成されたかと思います。

では、実際にモデルの定義ができたか確認してみましょう!

で作成したデータベースにアクセスします。

しっかりテーブルが作成できました!

サンプルのデータを挿入してみる

それでは、適当なデータを挿入してみましょう。

このとき、Userテーブルには管理者ユーザ(admin)を追加することにします。

早速、 sample_insert.py (ファイル名はなんでも良い)を作成しましょう!

SQLAlchemyでは、このようにデータをデータベースに追加が可能です。

データベースをいじる際には、 import models と import db を忘れないようにしましょう。

simple_insert.py を実行してみる!

では、 simple_insert.py を実行してみましょう!

すると、 models.py で定義された各モデルのコンストラクタ __init__()に、引数にとったデータが渡され、各テーブルに db.session.commit() で挿入されます。

確認

うまく挿入できたか確認してみましょう!

うまく挿入できていそうです!

adminサイトに入る前に

それでは、adminページに入りたいところですが、Djangoと違ってデフォルトで用意されていないので、管理者ページを作ります。

ということで、今から作成するのは、この3つになります。

  1. 管理者(admin)のログイン機能
  2. 管理者ページ(administrator.html)
  3. ログアウト機能

少々ややこしい部分も出てきますが頑張っていきましょう!

管理者(admin)のログイン機能

それでは、前回作成した admin.html からpostメソッドで受け取る /ad_login を作っていきます。

ルーティング作業ですので、 urls.py に加筆していきます。

ログイン機能

ログイン機能には、様々な機能が必要です。

  1. usernameとpasswordがデータベースに存在するか
  2. usernameとpasswordが一致するか
  3. そもそも入力フォームにそれぞれが入力されているか
  4. 以上3点が守られていない場合エラーメッセージを返す
  5. OKならば入力されたusernameでセッションを開始する

と、最低限必要な機能を挙げるだけでも、これだけあります。

また、getで /ad_login にアクセスされた場合に、余計な処理をせずにログインページへリダイレクトさせる必要もあります。

これらを実装していく前に、「1.usernameとpasswordがデータベースに存在するか」と「2.usernameとpasswordが一致するか」は、一つの関数として最初に定義してしまいましょう。

新しく認証用の関数を定義する auth.py を作成し、認証ができたか否かを返す関数 is_auth() を実装します。

また、「今現在ログイン状態にあるかないかを判定し、ログインしていなければログイン画面へリダイレクトさせる」機能をもつ authorized() も一緒に実装してしまおうかと思います。

auth.py

実装例は、以下のようになります。

is_auth() では、まずデータベースのUserテーブルから、「username」と「password」をセットでリストとして持ってきます。

users = db.session.query(User.username, User.password)

そのリスト内に、引数にとったusernameとpasswordに対して一致するものがあればTrueを返し、なければFalseを返すシンプルな関数です。

authorized() もシンプルで、cookieに「username」キーがなければリダイレクト、としているだけです。

urls.py

では、また urls.py に戻ります。

先ほど挙げた機能を urls.py に実装してみたいと思います。

新しく加筆した部分には # New! をつけていますので参考にしてください。

加筆したコード量は多いですが、一つ一つ丁寧にみていけば、どのような処理を行っているかはなんとなく理解できると思います。

Responderでは、今回実装した @api.route('/ad_login') のように処理をクラスでも記述することができます class AdLogin 

  1. async def on_get(self, req, resp) でget処理
  2. async def on_post(self, req, resp) でpost処理

そうすると、 async def on_get(self, req, resp) でget処理、 async def on_post(self, req, resp) でpost処理を書き分けることができますので、覚えておきましょう!

ログイン/ログアウト

また、Responderのログイン/ログアウトについては、 resp.set_cookie(key='名前', value='実際の値', expires='いつ破棄されるか', max_age='何秒後に破棄されるか')を使用します。

  1. ログインは、 expire=None max_age=None
  2. ログアウトは、 expire=0  max_age=0

ログインでは、 expire=None max_age=None としておき、ログアウトでは expire=0  max_age=0 とすれば機能が実現できます。

他にも、 resp.set_cookie()には引数は存在しますが、今回は簡略化のためスルーします。

また、まだ /admin_top のルーティングは終わってないので、このログイン機能は完全には機能しません

管理者ページ(administrator.html)

次に、先ほどの /admin_top のルーティングと、そのビュー administrator.html を作成していきます。

管理者ページでは、データベースの中身を視覚的に確認できるようにします。

最終的には、このページからデータベースへの追加や削除もできるようにしますが、とりあえずは表示のみを目指します。

/admin_top のルーティング

早速、 urls.py に /admin_top のルーティングを行なっていきます。

また、その際にQuestionテーブルとChoiceテーブルのデータを取得しておき、 administrator.html に渡す作業も実装していきます。

やっていることは先の is_auth() と少し似ていますね。

関数の冒頭で、cookieにユーザが存在しない(=ログインしていない)ときに、ログインページへリダイレクト authorized() させています。

こうすることで、 /admin_top に直接アクセスできなくさせています。

ビューを作る

それでは、ビューを作っていきましょう。

ビューは、前回のように作っていけば良いので説明は省略しますが、受け取ったデータの展開の仕方だけコードを見て理解しておきましょう。

今更ですが、ビューでの動的ページは、Jinja2と呼ばれるエンジンに従ったコーディングを行なっています。

{% %} の中に構文、 {{ }} の中には出力させたい変数を入れます。

詳細は、コードを見ながら覚えられると思います。

ビューの実装

ビューのコードは以下のように実装しました。

テーブルでデータベースの情報を表示する形をとりました。

「Add」ボタン、「Change」ボタン、「Delete」ボタンは、まだ実装していないので機能しません。

右上に表示される「ログアウトボタン」については、今から実装していきたいと思います。

ログアウト機能

さて、長くなりましたが、やっとで本記事最後のコーディングになります。

ログアウト機能は、とてもシンプルです。

セッションから抜けて、ログイン画面にリダイレクトさせるだけなので、以下のように urls.py に加筆します。

ログアウトは、先ほど言ったようにcookieを破棄するまでの時間を0とすればOKです。

ちなみに、cookieの中身を見たい場合は print(req.cookies) で見ることができます

( resp ではなく req です!)

もし、うまくいかない場合は、デバッグ用で活用してくださいね。

adminサイトに入る

ここにきて、やっとでチュートリアルに戻ってきました!

まずは、サーバを起動して、http://127.0.0.1:5042/adminにアクセスしてみます。

ログイン成功

次に、ログイン画面を確認してみたいと思います。

それぞれに「admin」「responder」と入力して、

ログインしてみましょう!

うまくデータベースの中身が表示できました!

ログイン失敗

それでは、わざとユーザ名やパスワードを間違えて、エラーメッセージが出るかも確認してみます。

【error1】


【error2】

問題なさそうですね!

あとは、理者ページからデータベースの操作ができれば管理者ページは完成になります。

こちらは、次回に続きます!

第3回へつづく!

今回は、「データベースの構築」「モデルの定義」と、ボリュームのある回となりました。

ですが、ここを乗り越えると、Webアプリケーション初心者でも、なんとなく勝手が分かってくるのではないでしょうか?

次回も、「データベースとの連携」を含んだ話が続きますが、あともう少し頑張っていきましょう!

第3回の記事はこちら

【全編まとめ】Responderを使ってDjangoチュートリアルをやってみた

こちらの記事もオススメ!


urls.py

最後に、前回から更新(加筆)されたurls.pyの全体を載せておきます。

ディレクトリ構成

あとは、現在のディレクトリ構成も載せておきます。

 

書いた人はこんな人

広告メディア事業部
広告メディア事業部
「好きを仕事にするエンジニア集団」の(株)ライトコードです!

ライトコードは、福岡、東京、大阪の3拠点で事業展開するIT企業です。
現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。
いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。

システム開発依頼・お見積もり大歓迎!

また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」「WEBディレクター」を積極採用中です!
インターンや新卒採用も行っております。

以下よりご応募をお待ちしております!
https://rightcode.co.jp/recruit

関連記事

採用情報

\ あの有名サービスに参画!? /

バックエンドエンジニア

\ クリエイティブの最前線 /

フロントエンドエンジニア

\ 世界を変える…! /

Androidエンジニア

\ みんなが使うアプリを創る /

iOSエンジニア