Python – Django2.0で手早くアプリを作る その弐

前回の記事ではLinuxにPython環境を整え、Djangoインストール後にブラウザで見れるところまでやりました。今回はモデルを中心に作業していきます。このモデルというのは簡単にいうと、データの集合と、それにアクセスする手段などをまとめたものです。そのためにデータベースを使います。

DjangoデフォルトのデータベースはSQLite3になっています。SQLiteは高速に動くため、昔からスタンドアロンのアプリ(Windowsソフト)などに同梱されて使われていたりします。

ただ今回はほとんどの現場で使われているであろうMySQL(MariaDB)を設定したいと思います。

MySQLの中身はMariaDBです。ただ、コマンド名をMySQLだったときと同じにするため、MySQLという名前もまだ残っているという状態です。歴史的にいろいろあったのです。ヒントはOracle社です。あまり細かいことは気にしないほうが寝覚め良いです。

MySQL(MariaDB)を使う設定

root設定のtodo/settings.pyを開き、データベースやタイムゾーンなどの設定をおこないます。

データベースはホスト内にインストールしたMySQL(MariaDB)を使いますので、インストールしてない人はこの時点でインストールを済ませてください。Amazon LinuxやCentOSならインターネットでググればすぐに出てきます。

そして以下の設定でデータベースへの接続を行います。

  • データベース名: todo
  • ユーザ名: vagrant
  • パスワード: vagrant
  • ホスト: localhost
  • ポート: 3306

ユーザ名とパスワードがvagrantなのは特に意味はありませんが、vagrantを使った仮想環境であれば、ほぼすべてのユーザ名とパスワードをvagrantにしておくと作業が楽なので、その流れで名付けてるだけです。実際の運用では絶対にこんな簡単な名前とパスワード使っちゃダメです。

早速rootアプリの設定に書き込みます。

todo/settings.py

次に、pythonでMySQLを扱うためのライブラリをpipコマンドでインストールします。

これでpythonからMySQLを便利に使うことが出来るようになりました。
次はそれをDjangoに教えてあげる必要があります。

コマンドで何度も使っているmanage.pyですが、このファイルにmysqlの設定を書き込むのが定石です。

todo/manage.py

上記のように2行追記すればOKです。

マイグレーション

さて、MySQLはインストールされ、Pythonからもアクセス可能であり、Djangoからもアクセス可能になったので、今度はDjangoにデータベースで使うテーブル一式を自動的に作ってもらいます。この作業をマイグレーションといいます。

簡単に言うと、別の環境でも同じ環境を構築出来るように、ファイルに構造などをまとめておくのですが、その構造の更新を自動で反映させることと、実際にデータベースに反映させるという意味になります。

以下のコマンドでマイグレーションします。

実行結果

このmigrateコマンドはtodo/settings.pyINSTALLED_APPSを利用してマイグレーションされます。現在以下のようになっているはずです。

これらすべてのアプリで使用されるデータベーステーブルが自動的に作成されました。
試しにデータベースを覗いてみると、ちゃんといくつかのテーブルが作られているのが確認出来ます。

管理画面でのログインで使うユーザ認証などのテーブルが作られています。
これから独自のアプリ用モデルを作っていきます。

モデル設計

todoリストなので、以下のような構造があれば問題ないかと思います。

  • Task
    • id
    • 内容
    • 作成日

今回は単純なものを作りたいので、todoが達成されると消してしまいましょう。
リストからチェックを押すと、確認もなしに突然todoが削除されます。そういう仕様で一旦作ってみましょう。

list/models.py

Taskモデルの中で代入している変数task_textcreated_atは、データベーステーブルのフィールド名になります。クラスであるTaskがテーブル名になります。実際には小文字に変換され、アプリ名とくっついてlist_taskテーブルになります。

modelsクラスの中にはたくさんのフィールド指定用メソッドが用意されているので、それを利用してこのように型などのパラメータを指定します。

データベースを作ってテーブルも作ったことがある人ならならば、Djangoのリファレンスマニュアルを参考にすればいくつか自由にフィールド設定出来ると思います。

早速このクラスをマイグレーションしてみましょう。
このコマンドはマイグレーションで使われるファイルを作成するためのコマンドです。最初に行ったmigrateコマンドでも、0008などの名前がついたファイルが使われましたが、それらのファイルを作るコマンドになります。

実行結果

さて、このlist/migrations/0001_initial.pyを見てましょう。

見事にPython(Django)のファイルになっています。そしてこのファイルをDjangoが実行すれば、別の環境であっても、同じデータベーステーブルが作成されるということです。

このファイルは基本的にDjangoが作り、使うのもDjangoですので、手はつけずにそのまま閉じておきましょう。

ちなみにこのファイルをSQLとして表示させることが出来ます。
以下のコマンドを実行してみましょう。

実行結果

見事にSQLですね。マイグレーションするとこのSQLが発行されるということになります。SQLのほうがわかりやすいという人もたくさんいると思うので、このコマンドはありがたいですね。

さて、一番最初にやったマイグレーションのコマンドは以下でした。

今すでに新しくTaskテーブルを定義し、マイグレーションする際に参照されるファイル(list/migrations/0001_initial.py)が出来ている状態なので、改めて実行しましょう。

実行結果

これでデータベースには「アプリ名_モデル名」、つまりlist_taskというテーブルが実際に作られました。

データベースクライアントソフトなどを一切使わず、コンソールでシェルを叩いたり、pythonファイルを作るだけでここまで出来るのが、Djangoのマイグレーションのすごいところだと思います。

Djangoシェルでデータを投入

DjangoにはDjango専用のshellが用意されていて、テストケースやAPIを叩いたりするのに使えます。
このShellを使って、マイグレーションしたテーブルにデータを追加したり出来るのですが、返却値がID、つまり数字だったりします。できれば入力したテキストが表示されるとすごくわかりやすくなります。

そこで、メソッドをオーバーライトして、idではなくテキストを表示するように変更しておきます。オーバーライトするメソッド名は__str__です。

list/models.py

さて、シェルを起動してテストしてみましょう。
まずはタスクを追加し、表示してみます。

まだ何もデータがないので空の配列(QuerySet)が返ってきました。

次は、タスク名と作成日を1件だけ入力してみます。作成日の指定で必要になるので、django.utilsのtimezoneを読み込みます。
タスク名には「buy milk(牛乳を買う)」というテキストを設定してみます。作成日は現在時刻を設定します。

これで保存されました。
試しに中身を見てみましょう。

簡単ですね。タイプミスしなければサクサク作業がはかどります。

最初に実行したコマンドをここでもう一度実行してみましょう。

この<QuerySet [<Task: buy milk>]>ですが、__str__メソッドでtask_textを返却するようにオーバーライトしたので、人間がわかりやすい状態で表示されるようになっています。このオーバーライトがなければ、<QuerySet [<Task: Task Object (1)>]>というように、数字になってしまい、わかりにくくなってしまいます。

この__str__メソッドのオーバーライトは重要なので忘れないようにしましょう。

ここでは全部で10個ほどのタスクを入力しておきます。django1.4からバルク(大量)インサートが可能になったようですので、ここでは一気にまとめて入れてみます。

てか、これはこれで面倒くさいっすね。ざけんなボケェ!!!!

上記テキストをコピーして、行頭の「…」を削除し、インデントを適切にした状態で全行コピーし、それをシェルに貼り付けると楽かも。

では、ちゃんと入ったか確認しましょう。

問題なさそうです。ちゃんと10個入りました。

ちなみに以前までおっちゃんが日本語翻訳担当代表になっていたWindows用データベースクライアントソフトのHeidiSQLでみてみると、ちゃんとしっかりデータ入ってることが確認出来ました。

モデルの中身を表示する

データを定義したり加工したり取得するのはモデルの仕事ですが、データを画面に表示するのはビューの役目です。
まずはビューを見てみましょう。

list/views.py

前回のままになっているはずなので、indexしか定義されていません。

ここにいろいろ追加していきます。まずは、HTTPアクセスでのレスポンス処理を行うモジュール「HttpResponse」と、ページが存在しない場合の処理を行うモジュール「Http404」が合わさったショートカットモジュール「get_object_or_404」を使う宣言をします。

このショートカットモジュールはすごく便利で、例えばtry:~exceptでいちいち判定していた例外処理などを全く記述しなくて済みます。率先して使いましょう。ただし、元になってるHttp404モジュール、HttpResponseモジュールの存在を知らないと、ゆとりすぎによりおっちゃんに殴られますので覚悟しておいてください。

実はrenderもショートカットモジュールで、「HttpResponse」と「Loader」をあわせたものです。この2つでテンプレート読み込み、コンテクスト指定で変数を割り当ててたのが、めちゃめちゃ簡略化されます。

以下のように書き換えます。

やってることはそれほど難易度高くありません。

indexでは、task_listにselectした内容を配列で入れています。SQLとフレームワークの間を取り持つORMという仕組みなので、SQLは書かずにメソッドで指定します。order_byがそうです。そしてそのうち先頭から10件を取得するというPythonの配列シンタックスを行末につけています。取得した配列はテンプレート用に同じ名前の変数に代入しています。

detailは1つのタスクを表示するので、タスクidが必要です。そのidをプライマリキーとして持つデータを取得するため、「pk」という変数で指定しています。これがデータベーステーブルのプライマリキーという事になります。そしてtask変数にデータをいれてテンプレートに送っている、という処理になります。

さて、次は実際にテンプレート側で表示させるための作業になります。index.htmlとdetail.html(新規作成してください)を以下のように編集します。

list/templates/list/index.html

list/templates/list/detail.html

CSSフレームワークのUiKit3を使っているため、最小限なHTMLではありませんが、セマンティックなHTMLにはなっています(しかもレスポンシブです)。

さて、detailは今回新規に作りましたので、ルーティングとなるlist/urls.pyに登録して置かなければなりません。

list/urls.py

<int:task_id>/の部分が、/数字/のURLが来たらdetailビューを返せという処理になります。
このurls.pyはURLとビューを紐付ける処理を司っているため、必ず記述する必要があります。

正規表現をつかってURLのパスを分ける方法もあります。

それでは開発用サーバを起動してブラウザで確認してみましょう。

以下のような画面が表示されるはずです。

/list/

/list/5/

おわり

次回はタスクを追加/削除/編集する処理を追加し、CRUDなインタフェースを構築します。
その他、各種ボタンなども追加し、アクセシビリティ向上も行いたいと思います。