トップ 一覧 ping 検索 ヘルプ RSS ログイン

Django 最初のアプリケーション 3の変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
!!!Django 最初のアプリケーション 3 (Viewの作成)
[Django][Python][[[前|Django 最初のアプリケーション 2]]][[[次|Django 最初のアプリケーション 4]]]

Pythonの概要も分かり易い.
{{amazon 477413760X}}

*[The Django Book|http://www.djangobook.com/en/1.0/]

*http://docs.djangoproject.com/en/dev/intro/tutorial03/#intro-tutorial03
を参考にサンプルアプリケーションを作成してみる

!!方針
""Djangoアプリケーションにて、ビューは、Webページの『型』であり、特定の機能や、テンプレートを提供する。
::たとえば、ブログアプリケーションでは以下のようなビュー。
*ホームページ - 最新の2、3のエントリを表示
*エントリの詳細ページ - あるエントリへのパーマリンク
*年別アーカイブページ - ある年のエントリを月別表示
*月別アーカイブページ - ある月のエントリを日別表示
*日別アーカイブページ - ある日のエントリを表示
*コメントページ - エントリへのコメント

::サンプルとして作成している Poll アプリケーションでは、以下の4つのビューを持たせる
*アーカイブページ - 最新の2、3の調査を表示
*詳細ページ - 調査の質問を表示。結果は表示せず、投票フォームを表示
*結果ページ -  調査結果のページ特定の調査についての結果
*投票ページ -  特定の調査に対する投票を選択する

""Djangoではビューをシンプルな Pythonの関数で表現する

!!URLの設計
!URLの構造を設計
*最初に、URLの構造を設計する
*これには、URLconfから呼び出される、Pythonのモジュールを作成する
*URLconfは、DjangoがURLとPythonコードを結びつける

*Djangoで作成されたページにアクセスすると、システムは ROOT_URLCONF設定を探す
*ROOT_URLCONFはPythonのドット区切り文法で記述された文字列
*Djangoはこのモジュールをロードし、呼び出されたURLパターンで、モジュールレベル変数を探す
*URLパターンは、以下の書式の[[タプル|Python サンプルコード]]
 (正規表現, Python コールバック関数 [, オプションのディクショナリ])

*Djangoは、最初に正規表現が一致するまでリストを下っていく
*一致するものが見つかったら、Djangoは、HttpRequestオブジェクトを最初の引数として、キーワード引数として、正規表現から捕捉された値、オプションで任意のディクショナリ(タプルの3つ目の項目)を伴って、Pythonコールバック関数を呼び出す

!オブジェクト詳細
**[HttpRequestオブジェクト|http://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest]
**[Request、Responseオブジェクト|http://docs.djangoproject.com/en/dev/ref/request-response/#ref-request-response]
**[URLconf (URL dispatcher) |http://docs.djangoproject.com/en/dev/topics/http/urls/#topics-http-urls]

!urls.pyの編集
*[[最初のアプリケーション 1|Django 最初のアプリケーション 2]]で、django-admin.py startproject mysite を実行したとき、mysite/urls.py にデフォルトの URLconfを作成している。
*自動的に、settings.pyファイルのROOT_URLCONF 設定 にて、そのファイルを指定している
 ROOT_URLCONF = 'mysite.urls'

*mysite/urls.pyを以下のように編集
 from django.conf.urls.defaults import *
 
 # Uncomment the next two lines to enable the admin:
 from django.contrib import admin
 admin.autodiscover()
 
 urlpatterns = patterns('',
     # Example:
     # (r'^mysite/', include('mysite.foo.urls')),
     (r'^polls/$', 'mysite.polls.views.index'),
     (r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'),
     (r'^polls/(?P<poll_id>\d+)/results/$', 'mysite.polls.views.results'),
     (r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),    
     
     # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
     # to INSTALLED_APPS to enable admin documentation:
     # (r'^admin/doc/', include('dhttp://typea.info/tips/wiki.cgi?action=EDIT&page=Django+%BA%C7%BD%E9%A4%CE%A5%A2%A5%D7%A5%EA%A5%B1%A1%BC%A5%B7%A5%E7%A5%F3+3&artno=2jango.contrib.admindocs.urls')),
 
     # Uncomment the next line to enable the admin:
     (r'^admin/(.*)', admin.site.root),
 )

!リクエストパラメータの解析
上記の例では、"/polls/23/"というリクエストがあった場合、DjangoはPythonモジュールをロードする。これは、r'^polls/(?P<poll_id>\d+)/$' にマッチするためであり、 mysite/polls/views.py.からdetail()関数が以下のように呼び出される。
 detail(request=<HttpRequest object>, poll_id='23')
*poll_id='23' の部分は、(?P<poll_id>\d+)から来ている
*丸括弧でパターンをを囲うことにより、テキストの一致を『捕捉』しビュー関数に引数として送信する。
*?P<poll_id> がパターンにマッチした場合の名称を定義している。
*\d+ は正規表現で数字の連続

!!最初のビュー
!ViewDoesNotExistエラー
*まだ、ビューを作成していないので、http://192.168.24.14:8080/polls/ にアクセスしても、以下のようにViewDoesNotExistエラーが表示される

{{ref_image django_firstapp24.jpg}}

*これは、index() 関数を mysite/polls/views.py. に実装していないため。
!シンプルビューの実装
*mysite/polls/views.py に以下を記述してみる
 from django.http import HttpResponse
 
 def index(request):
         return HttpResponse("Hello, world. You're at the poll index.")
                                                                        
{{ref_image django_firstapp25.jpg}}
テキストを出力するシンプルなビューが作成された

!引数を取るビューの実装
*引数をとる以下の関数を追加し、http://192.168.24.14:8080/polls/34/ にアクセス
 def detail(request, poll_id):
        return HttpResponse("You're looking at poll %s." % poll_id)
{{ref_image django_firstapp26.jpg}}
URLに入力したパラメータを取得できている

!!実際になにかするビュー
!簡単なビューの作成
*ビューは次の2つのうちどちらかを行う責任がある。
**リクエストされたページのコンテンツを含んだHttpResponseオブジェクトを返す
**Http404のようなエラーを返す

*先ほどの例で、HttpResponseにメッセージを直接与えたように、Pollの最新の5件を出力するようにハードコーディングしてしまうと、ページの見た目を変えるためにPythonのコードに手を加えなければいけなくなってしまう。Pythonからデザインを分離するために、テンプレートを使用する。

*以下のコードはpolls/index.htmlテンプレートをロードし、Contextというテンプレート変数名とPythonオブジェクトのディクショナリを引き渡す
 from django.template import Context, loader
 from mysite.polls.models import Pollfrom django.http import HttpResponse
 from mysite.polls.models import Poll
 from django.http import HttpResponse
 
 def index(request):
         latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
         t = loader.get_template('polls/index.html')
         c = Context({
              'latest_poll_list': latest_poll_list        
         })        
         return HttpResponse(t.render(c))

*ページをリロードするとテンプレートがまだないため、以下のようなエラーとなる
 TemplateDoesNotExist at /polls/
 polls/index.html

*[[最初のアプリケーション 2|Django 最初のアプリケーション 2]]でsetting.pyに指定したTEMPLATE_DIRS のディレクトリ以下に、pollsディレクトリを作成し、index.htmlファイルを作成する
*loader.get_template('polls/index.html') は、"[テンプレートディレクトリ]/polls/index.html"をファイルシステム上では指すようになる

'''index.html'''
 {% if latest_poll_list %}
         <ul>
         {% for poll in latest_poll_list %}
                 <li>{{ poll.question }}</li>
         {% endfor %}
         </ul>
 {% else %}
         <p>No polls are available.</p>
 {% endif %}

{{ref_image django_firstapp27.jpg}}
::ショートカット : render_to_response()
*テンプレートをロードするのによく使われる方法は、コンテキストとHttpResponseオブジェクトをテンプレートとともに詰めて返す。

書き直してみる
 from django.shortcuts import render_to_response
 from mysite.polls.models import Poll
  
 def index(request):
         latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]          
         return render_to_response('polls/index.html',{'latest_poll_list': latest_poll_list})
上と同じ結果が得られる

!404エラー
Poll詳細ビューを作成してみる
 from django.http import Http404from mysite.polls.models import Poll
       :
 def detail(request, poll_id):
         try:
                 p = Poll.objects.get(pk=poll_id)
         except Poll.DoesNotExist:
                 raise Http404
         return render_to_response('polls/detail.html', { 'poll': p })
*Poll のIDが見つからない場合、HTTP 404エラーを返す

*detail.htmlにとりあえず、以下の内容を記述
 {{ poll }}

*存在するIDを指定
{{ref_image django_firstapp28.jpg}}
*存在しないIDを指定
{{ref_image django_firstapp29.jpg}}

::ショートカット : get_object_or_404()
*Djangoはこのような場合にもショートカットを提供
 from django.shortcuts import render_to_response, get_object_or_404
 from mysite.polls.models import Poll
 
 def detail(request, poll_id):
         p = get_object_or_404(Poll, pk=poll_id)
         return render_to_response('polls/detail.html', { 'poll': p })

*get_list_or_404()関数も、同様に動作する。get()の代わりに、filter()を利用することを除いて。リストが空の場合、404エラーを返す。
!テンプレートシステムを利用する
*detail()ビューは、次のような感じ
 <h1>{{ poll.question }}</h1>
 <ul>
 {% for choice in poll.choice_set.all %}
         <li>{{ choice.choice }}</li>
 {% endfor %}
 </ul>
{{ref_image django_firstapp30.jpg}}
*テンプレートでは、ドット記法で、変数の属性にアクセスできる。{{ poll.question }}のように
*詳しくは[テンプレートガイド|http://docs.djangoproject.com/en/dev/topics/templates/#topics-templates]参照

!!URLconfs
!簡単にする
*各コールバック関数共通の、「mysite.polls.vews」をプレフィックスとして外だしできる
 urlpatterns = patterns('mysite.polls.vews',
     (r'^polls/$', 'index'),
     (r'^polls/(?P<poll_id>\d+)/$', 'detail'),
     (r'^polls/(?P<poll_id>\d+)/results/$', 'results'),
     (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'),
 )
!分割する
*Pollアプリケーションの可搬性を高める
*今までの、mysite/urls.py を mysite/polls/urls.py にコピー
::mysite/urls.py
*mysite/polls/urls.pyを取り込む
 urlpatterns = patterns('',
     (r'^polls/', include('mysite.polls.urls')),
 )
::mysite/polls/urls.py
*正規表現から、polls/ を取り除く。
*こうすることにより、/polls/から、ほかのURLへの移動も簡単になる
 urlpatterns = patterns('mysite.polls.views',
     (r'^$', 'index'),
     (r'^(?P<poll_id>\d+)/$', 'detail'),
     (r'^(?P<poll_id>\d+)/results/$', 'results'),
     (r'^(?P<poll_id>\d+)/vote/$', 'vote'),
 )

[[[前|Django 最初のアプリケーション 2]]][[[次|Django 最初のアプリケーション 4]]]