Django – クラスベースビューの基本

概要

Djangoのビューを実装するのに、関数で書く方法と、Viewクラスやその派生クラスを継承して必要なメソッドをオーバーライドする方法がある。

Djangoのオーソドックスな書き方ではクラスベースビューのListViewなどを利用し、コード量を減らすことが推奨されている。

ここでは関数による方法とViewクラスの継承クラスによる方法の2つを比較する。

基本形

テンプレートの準備

ビューからパラメーターを受け取り、単にそれを表示するテンプレートを準備する。ここではviewtestというアプリケーションを想定し、準備するテンプレートファイルはindex.htmlとする。

関数によるビューの実装

views.pyの記述

アプリケーションディレクトリー下のviews.pyファイルに、indexビューを関数で定義する。ビューではテンプレートに渡すパラメーターを文字列'Hello!'としている。

urls.pyの記述

アプリケーションのサブディレクトリーfunctionから、同じアプリケーションのindexビューへのルーティングを定義する。この例の場合localhost:8000/viewtest/functionのようにURLを指定し、ブラウザーでアクセスすることになる。

ここでサーバー起動状態でブラウザーに先のURLを指定すると、ブラウザーに以下のように表示される。

関数ビューの場合、GETを含むリクエストに対してurls.pyに従ってビューが呼び出され、その内容が実行される。

クラスベースビューによる実装

関数によるビューと同じ処理をクラスベースのビューで実装してみる。ここでは比較のために、関数ビューのコードを残してクラスベースビューのコードを追加していく。

views.pyの記述

クラスベースのビューは、Viewクラスやその派生クラス(ListViewなど)を継承し、getpostなどのリクエストに対応したメソッドを記述する。ここではGETリクエストにのみ反応させるため、getメソッドを実装している。

Viewクラスではgetメソッドは定義されていないが、Viewの派生クラスでGETメソッドでのリクエストがあるとViewクラスのhandlerが実行され、View.get()が実行される。そして派生クラスでget()を定義しているとこれがオーバーライドされたメソッドとして実行される。

参考:Django ViewではHttpメソッド名の関数を定義することができる

urls.pyの記述

クラスベースビューによるメソッドが呼び出されるようにアプリケーションのurls.pypath関数を追加する。

関数ベースの場合はpath関数の第2引数に関数表現のビューモジュールを指定したが、クラスベースの場合はIndexViewの親クラスViewas_view()メソッドを指定している。as_view()メソッドは内部関数view()を通してdispatchメソッドを返すので、結局パスが解決されるとdispatchメソッドが呼び出されることになる。

ここでサーバー起動状態でlocalhost:8000/viewtest/classなどとURLを指定すると、ブラウザーに以下のように表示される。

URLパラメーターを含む場合

関数によるビューの実装

urls.pyの記述

URLパラメーターを含む場合、URLパターンに型名やパラメーター名を入れる。

views.pyの記述

ルーティングで記述したパラメーター名をビュー関数の引数に指定し、これをテンプレートに渡す。

ここでサーバー起動状態でlocalhost:8000/viewtest/function/1などとURLを指定すると、ブラウザーに以下のように表示される。

クラスベースによる実装

urls.pyの記述

URLパターンにURLパラメーターを記述する方法は関数の場合と同じ。クラスベースビューの場合はas_viewメソッドの実行結果を渡す。

views.pyの記述

クラスベースビューの場合、getなどのメソッドの引数にパラメーターを指定する。引数の指定パターンは関数の場合と同じ。

ここでサーバー起動状態でlocalhost:8000/viewtest/class/2などとURLを指定すると、ブラウザーに以下のように表示される。

GET/POST処理

関数によるビューの実装

テンプレートの準備

GETで表示されるページにフォームを追加し、送信先をfunctionサブディレクトリー、メソッドをPOSTとする。

urls.pyの記述

今回のindexテンプレートはGET、POST両方のリクエストから呼び出されるため、functionサブディレクトリーのルーティング1つ。

views.pyの記述

リクエストメソッドの違いはrequest.methodの文字列で判定して処理を分ける。GETリクエストの場合は1つ目のifブロックが実行され、テンプレートに文字列'GET!'が渡される。またPOSTリクエストの場合は2つ目のifブロックが実行され、テンプレートには文字列'POST!'が渡される。

ここでサーバー起動状態でlocalhost:8000/viewtest/functionなどとURLを指定すると、views.index関数でGETに対応したifブロックが実行され、ブラウザーに以下のようにGET!と表示される。

このページで「送信」ボタンを押すと、今度はviews.index関数でPOSTに対応したifブロックが実行され、ブラウザーにPOST!と表示される。

クラスベースによる実装

テンプレートファイルの準備

POSTに対する処理を関数の場合と分けるため、送信先のURLのサブディレクトリーをclassとする。

urls.pyの記述

GET/POSTに関わらず、classサブディレクトリーでのリクエストを受け取った場合には、IndexViewクラス(のインスタンス)に処理を渡すように定義。

views.pyの記述

ルーティングで

ここでサーバー起動状態でlocalhost:8000/viewtest/classなどとURLを指定すると、views.IndexViewクラスでオーバーライドしたgetメソッドが実行され、ブラウザーに以下のように表示される。

このページで「送信」ボタンを押すと、今度はviews.IndexViewクラスでオーバーライドしたpostメソッドが実行され、ブラウザーに以下のように表示される。

クラスベースビューの基本のまとめ

要点

基本のクラスベースビューの要点は以下のとおり。

  • Viewクラスを継承したクラスを定義
  • GETやPOSTなどに対応したメソッドを定義
  • ルーティングでは、継承先のクラスの.as_view()メソッドを渡す

views.pyの記述

  • django.views.genericパッケージのViewモジュールをインポート
  • Viewクラスを継承したクラスを定義
  • getメソッド、postメソッドなどを定義
    • 第1引数はself
    • 第2引数はrequest
    • パラメーターがあればそれ以降
  • getメソッドの記述内容は、関数ベースの場合の内容と同じ
    • たとえばrender(request, 'target_page')

urls.pyの記述

  • urlpatterns属性のpath関数の第2引数でビュークラスを指定し、このときas_viewメソッドを指定する
    • たとえばpath('sub_dir', views_dir.MyViewClass.as_view())

 

Django – URLパラメーター

URLパラメーターの送信

HTTPリクエストで、以下のようにURLにパラメーターを付して送り、これをDjangoで受け取って処理する手順。

ここではparamtestアプリケーションでパラメーターとして100が送信されるとする。

ルーティングの設定

まずURLに含まれるパラメーターを認識するため、ルーティングを設定する。アプリケーションのurls.pyで、パラメーターを受け取るために以下のように記述する。

<int:....>によってパラメーターが整数形式であることを明示していて、整数以外の値が渡された場合は404エラーとなる。

ビューの記述

ルーティング先のviews.indexでは、このパラメーターを引数で受け取る。以下の例では、受け取ったパラメーターをそのままテンプレートに渡している。

テンプレートが以下のようになっていれば、URLで与えたパラメーターの値がブラウザーにそのまま表示される。

 

 

Django – Tutorial – テンプレート

概要

DjangoドキュメントのチュートリアルPart3中”Write views that actually do something“の冒頭でビュー関数でのモデル操作を実装した後、テンプレートファイルを使った表示を実装している。

テンプレートの基礎についてはこちらを参照。

テンプレートディレクトリー/ファイルの作成

テンプレートファイルの内容

pollsディレクトリー下にtemplatesディレクトリーを、その下にpollsディレクトリーを作成する。そのディレクトリー下に以下の内容でindex.htmlファイルを作成する。

これから、polls/viewsモジュールからこのテンプレートを参照するよう編集していく。

パスの書き方の注意点

テンプレートファイルのアンカータグは以下のように書かれている。

当初/polls/{{ ... }}の部分の先頭の'/'を抜かして書いてしまって、polls/{{ ... }}としたところ、URLが以下のようになってしまった。

http://localhost:8000/polls/polls/2/

現在のアプリケーションからの相対パスになってしまったためで、

http://localhost:8000/polls/ + /polls/2/

と解釈されてしまう。先頭のスラッシュを入れるとホスト名をルートとするパスとなる。ただしこの記事の最後の方にあるDTLのurlタグを使うと、このような心配をしなくて済むようになる。

テンプレートの探索

ディレクトリー・ファイル構成は以下の通り。

config/settings.pyで、以下のように設定している。

  • INSTALLED_APPS'polls.apps.PollsConfig'を登録
    pollsが探索に含まれる
  • TEMPLATES'APP_DIRS'Trueに設定
    polls/templatesが探索に含まれる

ので、polls/templatesとそのサブディレクトリー下がテンプレートファイルの探索場所に含まれる。

ビューにおけるレンダリング

loaderによる標準形

ビューの編集

テンプレートファイルを導入した場合の標準形は以下の構成になる。

  • django.templateパッケージのloaderオブジェクトをインポート
  • loader.get_template('テンプレートへのパス')でテンプレートを読み込み
  • テンプレートのrenderメソッドでレンダリングした結果を、HttpResponseに渡す
    render(context, request)

動作確認

http://localhost:8000/pollsにアクセスすると、2つのリンクが表示される。

 

このHTMLのソースコードは以下のようになっている。

それぞれのリンクをクリックしたときの遷移先URLとブラウザー表示は以下の通り。

  • href="/polls/2/"
    • http://localhost:8000/polls/2/
    • You’re looking at question 2.
  • href="/polls/1/"
    • http://localhost:8000/polls/1/
    • You’re looking at question 1.

renderショートカット

loaderを用いた標準形では、

  1. テンプレートのローダーによってテンプレートファイルを読み込み、
  2. これをレンダリングした結果をHttpResponseに渡す、

という2段階の処理となっている。Djangoにはこれを1行で済ませるrenderショートカットが準備されている。renderショートカットを使って、indexビューをより簡潔にしてみる。

1行目のHttpResponseのインポートはまだ手を入れていない他のビュー関数のためで、renderによる処理には必要ない。loaderのインポートも不要で、必要なのは3行目のrenderのインポートのみ。

14行目がrenderショートカットを導入した効果で、この1行でリクエスト、テンプレート、contextの指定を済ませてレスポンスを返している。

render(request, 'テンプレートパス', context)

404エラーの実装

存在しないidへの反応

indexテンプレートではQuestionの2つの要素が表示され、それぞれid=1, 2をリクエストパラメーターとして渡している(href="/polls/1/"など)。ところがQuestionに存在しないidを指定したURLでアクセスすると以下のようなエラーがブラウザーに表示される。

このエラーの代わりに、404エラーで反応させたい。

例外処理による標準形

ビューの編集

現在のdetailビューは以下のような内容。

存在しないインスタンスを指定すると例外が投げられるので、それをキャッチして404エラーをレイズするようにする。

テンプレートの準備

またrenderで指定しているdetailテンプレートを、polls/template/pollsディレクトリーに以下の内容で作成しておく。

実行結果の確認

これで存在しないidの値を指定したときのエラーは以下のように変化する。メッセージがHttp404クラスのコンストラクターに与えたテキストになっている。

get_object_or_404ショートカット

Djangoには、上のような複数行の例外処理を一行で書くget_object_or_404ショートカットが準備されている。

以下のようにget_object_or_404ショートカットをインポートすると、1行でQuestionデータを取得し、存在しなければ404エラーをレイズしてくれる。

存在しないidを指定したときのエラー表示は以下のようになる。エラーメッセージの内容は固定されていて変更できないようだ。

なおsettings.pyDEBUGFalseにすると、ブラウザー表示は以下の2行のより簡素な内容になる

テンプレートシステム

DTLによる記述

先ほどのindexテンプレートの内容は1行で変数を表示するだけの内容だったが、これをテンプレートらしくDTL~テンプレート言語を使って以下のように書き換える。

そうすると大きな見出しでQuestionデータのテキストが表示され、そのQuestionデータに関連付けられたChoiceデータのテキストが箇条書きで表示される。

 

今回のDTLでは、オブジェクトの属性を得るのにドット検索が行われている。通常のPythonの場合リストや辞書型のオブジェクトの要素は[]で参照されるが、DTLではこの記述方法が使えない。代わりにドットを使って以下の順序で探していく

  1. 辞書型のキー
  2. オブジェクトの属性
  3. リストのインデックス

今回の例では、辞書型のキーで取得できず、オブジェクトの属性として取得に成功する。

URLのハードコーディング回避

ハードコーディングの問題

現時点でindexテンプレートのアンカー要素のURLは"/polls/{{ question_id }}/"と書かれている。

 

この場合にリンクが張られるdetailのURLはurlsで定義されていて、たとえば以下の通り。

http://localhost/polls/1

ここでプロジェクト進行中に以下のように変更することとなったとする。

http://localhost/polls/specifics/1

この場合、indexテンプレートのアンカー要素の内容を全て以下のように変更する必要がある。

href="/polls/specifics/{{ question.id }}/"

さらにindexテンプレート以外でもこのルーティングを使っている場合、その分だけ変更が生じてしまう。

ハードコーディングの回避

urls.pyの確認

まずpolls/urls.pydetailビューへのルーティングにname='detail'で名前が付けられていることに留意。

ビューの変更

index/view.py中、アンカー要素のURL部分を以下のように変更する。

  • href="..."のURL部分を{% url %}に入れ替え
  • このタグの引数に、urlsnameで指定した名前とパラメーターを書く

一般化した書き方は以下の通り。このとき、先頭や末尾の'/'は不要。

{% url 'urlsのnameで定義した名前' クエリーパラメーター %}

HTMLの確認

生成されるHTMLは以下の通り。

URLの変更

URLの変更が必要な場合、1箇所だけ、urlsの内容を変更すればよい。

以下のように生成されるHTMLもすべて変更される。

そして以下のようにアクセスできるようになる。

URLの名前空間管理

名前空間管理の必要性

DTLのurlタグで、ルーティングに付けた名前を使って抽象化することができた。ところが、先の例の場合pollsアプリケーションのdetailと同じ名前を他のアプリケーションでも使う場合、見分けがつかない。

そこで、ルート名がどのアプリケーションのものか分かるようにする必要がある。

urls.pyの編集

urls.pyに以下の1行を追加する。

indexテンプレートの編集

次にindexテンプレートの名前指定部分を、以下のように'アプリケーション名:ルート名'に変更。

この場合の実行結果は変わらないが、他のアプリケーションでもdetailという名前のルーティングがある場合でも、pollsアプリケーションの同名のdetailが識別される。

urlsapp_nameが定義されている状態でurlタグでpolls:を書かないと以下のエラーになる。

 

Django – Tutorial – ビューでの処理

概要

DjangoドキュメントのチュートリアルPart3中”Write views that actually do something“では、それまで単に文字列だけを返してブラウザーに表示させていたビュー関数に、ビューでの処理を記述している。そこではデータベ ースのデータを使った処理を例にしている。

チュートリアルではこれに続いてテンプレートの扱い方を示しているが、ここではモデル操作の実装だけを取り出して整理する。

index関数の編集

チュートリアルで示されているindex関数の編集内容は以下の通り。polls.models.Questionをインポートしていることに注意。

http://localhost:8000/polls/にアクセスすると、questionsテーブルに登録されているデータが日時の新しい順に、カンマで区切られて表示される。

チュートリアルではデータが1つしか登録されていなくて分かりづらいので、もう一つデータを登録してみる。

コードの内容

モデルインスタンスのソートと抽出

Questionモデルの全てのインスタンスをpub_dateフィールドの降順に並べ替えて先頭から5個取出し、そのQuerySetインスタンスをlatest_question_listに参照させている。

  • モデル.objects.order_by()でモデルのデータをソートした結果をQuerySetとして返す
  • '-pub_date'で降順にソート/昇順の場合は'pub_date'
  • [:5]はコレクションのスライスで、先頭から5個のデータ(インデックスが5未満のデータ)を取り出す

シェルで実行してみると以下の通り。

引数を'pub_date'に変更すると並べ替え順序が昇順になり、古いデータから並べられたセットが得られる。

またスライスを[:1]にすると、インデックスが0の要素だけが得られる。

出力文字列の構成

latest_question_listの各要素を', 'をデリミターとして結合している。各要素はQuestionモデルのインスタンスだが、__str__メソッドが実装されているので、参照するとquestion_textの内容が得られる。

 

Django – Tutorial – ビューへのルーティング

概要

DjangoドキュメントのチュートリアルPart3では、ビューへのルーティングやテンプレートの使い方などが詳しく書かれているが、このうちURLconf~ルーティングの部分を整理する。

urls.pyの配置や書き方についてはこちら

view関数の定義

まず、polls/views.pyファイルに3つのview関数(detail, results, vote)を追加する。

いずれのビューでも動作の本質は同じ。

  • リクエストからパラメーターをquestion_idとして受け取る
  • 各ビューで想定している処理の内容に即したテキストをHttpResponseで返す
  • その際、question_idの値もテキストに含めて返す

なおテキストにquestion_idの内容を文字列として含めるために、Pythonの構文を使っている。

"... %s ..." % 変数

urls.pyの設定

追加したview関数をこれに対応したURLリクエストから呼び出すため、ルーティングを追加する。

いずれのルーティングもpollsアプリケーションのビューに関するものなので、最初に作成したpolls/urls.pyに追記する。

確認

サーバー起動状態で各URLを入力したとき、呼ばれるview関数とブラウザー上の文字列は以下のとおり。

  • http://localhost:8000/polls/34/
    views.detail
    →You’re looking at question 34.
  • http://localhost:8000/polls/34/results/
    views.results
    →You’re looking at the results of question 34.
  • http://localhost:8000/polls/34/vote
    views.vote
    →You’re voting on question 34.

URLconf~ルーティングの仕組み

たとえばhttp://ドメイン名/polls/34/というURLでリクエストがあった時、Djangoは以下のように解釈を始める。

  1. settings.pyROOT_URLCONFの設定に従って、config.urlsモジュールを読み込む(モジュールファイルはconfig/urls.py
  2. urlsモジュール中のurl_patterns配列から、パターンを1つずつ順に走査していく
  3. URLパターンが'polls/'パターンまでマッチした時、それ以前のパターンを取り除いて、polls.urlsモジュールを読み込む
  4. polls.urlsモジュールでURLパターンの'<int:question_id>/'パターンまでマッチしてその後がないとき、これに対応するviews.detailモジュールを呼び出す
  5. detailモジュールでは<int:queston_id>の内容が引数のquestion_idに渡され、ビュー内での処理に使われる

なおsettings.pyROOT_URLCONFはデフォルトで以下のように書かれていて、まずconfig.urlsが読み込まれるようになっている。

またconfig.urlsは、チュートリアルの最初の方で以下のように編集済み。

またパラメーターについては<int:question_id>と定義されているので、localhost:8000/polls/abc/のようにパラメーターが整数として解釈されない場合にはパスが見つからず、Page not foundエラーになる。

 

Django-Tutorial-pollsアプリケーション

概要

Djangoドキュメントのチュートリアルに従って、mysiteプロジェクトを作成し、その中にpollsアプリケーションを作成する。

プロジェクトの作成

プロジェクトの作成django-adminで実行する。チュートリアルのプロジェクト構成ではmysiteディレクトリーの下にmysiteサブディレクトリーとしているが、ここではmysite/configという構成にした。

ディレクトリー構成は以下のようになっている。

settings.pyを以下のように編集する(初期設定の詳細はこちら)。

  • ローカルサーバーでの開発のため、ALLOWED_HOSTS'localhost'を設定
  • DATABASESはMySQL用に設定
  • その他、言語コードやタイムゾーンの設定

開発用サーバーを起動して、"Congratulations!"の画面を確認。

pollsアプリケーションの作成

startappコマンドでpollsアプリケーションを作成。

manage.pyは実行可能ファイルなので、以下でも作成できる。

pollsアプリケーション作成後の構成は以下の通り。

view関数の定義

view関数はMTVの構成要素の一つで、URLからルーティングされ、モデルのデータ操作やブラウザー表示のための様々な処理を実装するもの。MVCモデルのコントローラーに相当する。

一般的にはview関数の戻り値にはブラウザー表示のためのテンプレートを渡すが、ここでは最も単純に、単に文字列だけを返すようにする。

  • HttpResponseモジュールをインポート
  • view関数index()を定義
  • HttpResponseのコンストラクターの引数に文字列を渡し、そのインスタンスを戻り値とする

URL conf~ルーティング

URLからview関数index()へのルーティングを設定する。pollsアプリケーションのビューなのでpolls/urls.pyで定義する。アプリケーションのurls.pyはデフォルトでは作成されないので、新たに作成して次の内容とする。

pollsアプリケーションのurlsモジュールをプロジェクトに認識させるため、conf/urls.pyに記述を追加する。

  • django.urlsパッケージのincludeモジュールを追加でインポート
  • path関数でアプリケーションのurls関数をインポートし、アプリケーションのURLに紐づけ

確認

サーバーが起動した状態で、サブディレクトリーpolls/にアクセスする。今の構成ではlocalhost:8000/polls

ブラウザーの画面には、以下のテキストが表示される。

 

 

Django – Tutorial – admin

概要

Djangoのチュートリアル、管理者ページの部分を整理。

管理者ログインページ

Djangoのデフォルトの状態で、既に管理者の環境が準備されている。サーバーを起動してadmin/サブディレクトリーでアクセスすると、以下のような管理者ログイン画面が表示される。

管理者の作成

createsuperuserコマンドで管理者を作成する。

管理者のユーザー名、メールアドレス、パスワードを登録し、管理者アカウント作成。プロンプトの一部が日本語になっている。

パスワードを'admin'という文字列を含むかなり簡単なものにしたため「ユーザー名と似すぎています」という警告が出たが、ここはyesにしておいた。

管理者ログイン・インデックスページ表示

作成した管理者アカウントでログインすると管理者インデックスページへ。この段階では、pollsアプリケーションが管理者で操作できるようにはなっていない。

管理者へのアプリケーションの登録

管理者がpollsアプリケーションを操作できるようにするために、polls/admin.pyに記述を追加する。

  • Qustionモデルのインポート
  • adminサイトにQuestionモデルを登録

admin.pypollsパッケージ内にあるのでfrom .models ...としているが、from polls.models ...でもよい。

インデックスページを再表示させると、今度はQuestionsが見られるようになった。

データの内容表示

インデックスページのQustionsをクリックすると、登録済みデータが表示される。What’s up?と表示されているのは、models.pyQuestionクラスで__str__メソッドを定義したおかげで、デフォルトの状態だとQuestion object (1)と表示される。

What’s upをクリックすると、フィールド内容の編集画面に移る。

フィールド名のQustion textDate publishedは、models.pyQuestionクラスで定義したフィールド名になっている。

  • Question textは、クラス定義のプロパティーquestion_textのアンダースコアがスペースに、先頭が大文字に変換されたもの
  • Date publishedDateTimeFieldの引数に指定した'date published'の先頭が大文字に変換されたもの

たとえば上記の3行目をDateTimeField()とすると、画面表示は元のプロパティー名に即してPub dateとなる。

データの編集

Qustion textDate publishedの内容を変更して「保存して編集を続ける」ボタンを押すと、変更した内容が反映される。

もちろんデータベース上でも変更されている。

変更履歴

画面右上の「履歴」ボタンを押すと変更履歴画面に移り、Question textDate publishedが変更された履歴が表示される。

 

Django Tutorial – Pythonシェル

概要

Pythonシェルの環境下でモデル操作をしてみる。Pythonドキュメントのチュートリアルの流れに沿っている。Laravelのtinkerでの操作と似ている。

シェルの起動・終了

シェルの起動はmanage.pyshellコマンド。終了はexit()

モデルの操作

準備・確認

モデル操作の開始時にモデルのインポートが必要。

from アプリケーション.models import モデルクラス

タイムゾーン表示のためにtimezoneオブジェクトをインポート。

timezone.now()で現在時刻を表示してみる。内部的にはUTCで扱われているので、その時点の日本時間とは9時間ずれている。

モデルの全データの取得。まだデータは登録されていない。

データの作成・保存・編集

作成

Questionモデルのコンストラクターでデータを作成。この段階ではメモリー上に作成されただけで、データベースには保存されていない。

pprintvarsでデータの内容を確認してみる。

各フィールドを見てみる。まだデータベースに登録されていないので、idは空になっている。

保存

save()メソッドでデータベースに保存。

MySQLでテーブルへの保存を確認。

データベースに保存されたのでidがセットされた。

編集

データのquestion_textの内容を書き替えてデータベースに保存。

データベースを確認して内容が変更されていることを確認。

データの取得

Managerオブジェクト

個別のモデルごとにManagerクラスのインスタンスが生成され、モデルのobjectsメンバーとして準備される。データの取得やフィルタリングなど操作は、このインスタンスのメソッドによって行われる。

モデル.objects

all()による全データの読み込み

all()メソッドによってテーブルに登録された全データを読み込める。

モデルクラス.objects.all()

Qustionには1つだけデータが登録されている。

__str__の定義

データ表示が殺風景なオブジェクトの表示になっているが、これを変更してquestion_textchoice_textを表示させるようにする。具体的には各モデルに__str__メソッドを定義する。

これでデータ内容の表示がわかりやすくなった。

get()による1つのデータの抽出

get()メソッドで条件を指定してデータを1つ取り出せる。

モデルクラス.objects.get(条件)

id1のデータを取り出す。

該当するデータがない場合はModel.DoesNotExist例外、複数のデータが存在する場合はModelMultipuleObjectsReturned例外。以下はDoesNotExistの例。

主キー(primary key)を指定してでも取り出せる。Djangoではprimary keyのショートカットとしてpkが準備されている。

フィルターによる抽出

filter()メソッドでデータを抽出できる

モデルクラス.objects.filter(条件)

以下はid=1の条件で抽出した結果で、今回の例の場合はデータを1つ含むQuerySetが得られる。

存在しないidで抽出すると空のQuerySetが得られる。

文字列の前方一致の抽出例。引数のフィールドにアンダースコアを2つ(‘__‘)連ねて様々な条件を指定できる。フィルターの条件の書き方はこちらに整理した。

フィールド__条件=値

ここではフィールド__startswith='文字列'として、フィールドが指定した文字列で始まるデータを抽出している。

登録の年が同じデータを抽出する例。まず現在日時の年を取り出して変数current_yearにセットして、pub_dateの年がこれに等しいデータをフィルタリング。datetime型のフィールドの年の条件でフィルタリングするにはフィールド名__year=年とする。__yearのアンダースコアは2つ。

リレーションがあるモデル

親データに属する子データ群

親データに属する(これを参照している)データのManagerオブジェクトを取り出すには以下のように書く。

親データ.小文字の子モデル名_set

たとえば変数qが Questionモデルのid=1のデータを指している状態で、これに属するChoiceデータ群の全てを取り出すと以下のようになる。まだChoiceデータを1つも登録していないので結果は空。

親データに属する子データの作成

親データに関連付けられた子データを新たに作成するときは以下のように書く。

親データ.小文字の子モデル名_set.create(...)

qに関連付けられたChoiceデータを3つ登録。

MySQLでテーブルの内容を確認すると、Questionテーブルのid=1のデータを参照する3つのデータが登録されている。

<閑話休題>
“What’s up?”はくだけた言い方の挨拶で「調子はどう?」、「何か(変わりは)あったかい?」といった感じ。”Not much.”は「普通だよ」とか「特にないね」といった常套句のようだ。”The sky.”はupにひっかけて「(上は)空さ」というジョーク表現(無理やり日本語字幕にするなら「何かあったかい?」「暖かいね」とかなどと考えたが単なる駄洒落か・・・)。”Just hacking again.”はよくわからなかった。

子データのall/count/filter

登録されたデータをallメソッドで取り出してみる。

データの個数はcountメソッドで。

子データ群のフィルタリングは通常と同じように指定。

親データの条件によるフィルタリング

親データの条件でフィルタリングする場合、filter()の中で小文字の親モデル名を使うが、直接以下のように書くとエラーになる。

filter(小文字の親モデル名_フィールド__条件)→エラー

以下の例では、Choiceの親データquestionquestion_textフィールドの条件でフィルタリング仕様としてエラーになっている。

 

親データのフィールドの条件の場合、親データとフィールドの間のアンダーラインを2つにする。

親データ.子データ_set.filter(親データ__フィールド__条件)

たとえばQuestionChoiceの場合は以下のようになる。

q.choice_set.filter(question__フィールド__条件)

以下はテキストが'What'で始まる親データに属する子データを抽出している。

以下は登録年が今年の親データに属する子データを抽出している。

データの削除

まずテキストに'huck'(大文字小文字を問わない)を含むchoiceデータをデータベースから得る。

そのデータをdeleteメソッドでデータベースから削除。

モデル.delete()

MySQLで削除されていることを確認。

 

Django – filterの条件

一致

Case Sensitive

 BINARY field=値
field=BINARY 値
field=値
field__exact=値

Case Insensitive

field=値 field__iexact=値

大小比較

field>値 field__gt=値
field>=値 field__gte=値
field<値 field__lt=値
field<=値 field__lte=値

部分一致~LIKE

Case Sensitive

field LIKE BINARY 'text%' field__startswith='text'
field LIKE BINARY '%text' field__endswith='text'
field LIKE BINARY '%text%' field__contains='text'

Case Insensitive

field LIKE 'text%' field__istartswith='text'
field LIKE '%text' field__iendswith='text'
field LIKE '%text%' field__icontains='text'

何れかに一致~IN

field IN (...) field__in=[...]

範囲~BETWEEN

field BETWEEN min AND max field__range=[min, max]

日付の年・月・日の一致

DATE_FORMAT(date, '%Y') = 'year' date__year=year
DATE_FORMAT(date, '%m') = 'month' date__month=month
DATE_FORMAT(date, '%d') = 'day' date__day=day

NULLとの比較

field IS NULL field__isnull=True
field IS NOT NULL field__isnull=False

 

Django – django-adminとmanage.pyの基本コマンド

実行方法

manage.py

プロジェクトルート直下、manage.pyファイルのある場所で実行

コマンド

作成・起動

startproject
$ django-admin startproject プロジェクト名

  • プロジェクト作成
startapp
$ ./manage.py startapp アプリケーション名

  • アプリケーション作成
runserver
$ ./manage.py runserver [IPアドレス[:ポート]]

  • 開発用サーバーの起動

シェル

shell
$ ./manage.py shell

  • Pythonシェル起動
dbshell
$ ./manage.py dbshell

  • settings.pyDATABASESで設定したDBMSのシェル起動

チェック・確認

check
$ ./manage.py check

  • プロジェクトの不具合有無のチェック
dumpdata
$ ./manage.py dumpdata

  • データベースの内容をダンプ
inspectdb
$ ./manage.py inspectdb

  • モデルクラスの内容を表示

マイグレーション

makemigrations
$ ./manage.py makemigrations

  • models.pyに基づくマイグレーションファイルの作成
showmigrations
$ ./manage.py showmigrations

  • マイグレーションファイル・状態の表示
migrate
$ ./manage.py migrate

  • マイグレーション実行
migrate~ロールバック
$ ./manage.py migrate アプリケーション名 マイグレーション名

  • アプリケーションのマイグレーションが実行済みのときは手前までロールバック
  • 未実行の時はマイグレーション

その他

$ ./manage.py makemessages

$ ./manage.py compilemessages

$ ./manage.py createsuperuser

$ ./manage.py changepassword

・・・