Django初級手冊3-檢視層與URL配置

Solon Tan發表於2014-02-27

設計哲學

在Django中一個檢視有指定函式和指定模版組成。
對於某些特定的應用應該分成若干檢視。例如部落格系統

  • Blog主頁面
  • 詳細頁面入口
  • 基於年的頁面展示
  • 基於月的頁面展示
  • 基於天的頁面展示
  • 評論行為(action)

而對於投票應用,則由

  • 投票主頁
  • 投票細節頁面
  • 投票結果頁面
  • 投票行為(action)

在Django中,頁面由檢視(views)表達,而檢視由一個簡單的函式(成員函式)展示。Django通過URL來精確匹配一個檢視,即URLconfs

檢視層的編寫

1. 編寫應用試圖polls/views.py

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the poll index.")

2. 編寫應用URLpolls/urls.py

from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
    url(r'^$', views.index, name='index')
)

3. 編寫專案URL

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^polls/', include('polls.urls')),
    url(r'^admin/', include(admin.site.urls)),
)

URL的引數

  1. 第一個引數為正規表示式,用r開頭的原始字串不會被Python轉義
  2. 第二個引數指定檢視函式
  3. 第三個引數,一般不用
  4. 第四個引數為此URL取別名

通過URL傳遞引數

1. 編寫URL

(?P<poll_id>\d+)指該部分的URL為一個引數,引數的名字由?P<poll_id>指定,\d+只由一個或更多的陣列組成。
from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
    # ex: /polls/
    url(r'^$', views.index, name='index'),
    # ex: /polls/5/
    url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
    url(r'^(?P<poll_id>\d+)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
    url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'),
)

2. 接收引數

def detail(request, poll_id):
    return HttpResponse("You're looking at poll %s." % poll_id)

def results(request, poll_id):
    return HttpResponse("You're looking at the results of poll %s." % poll_id)

def vote(request, poll_id):
    return HttpResponse("You're voting on poll %s." % poll_id)

與資料庫連線,顯示其內容

1. 編寫檢視函式

from polls.models import Poll

def index(request):
    latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
    output = ', '.join([p.question for p in latest_poll_list])
    return HttpResponse(output)

2. 建立模版

這裡推薦模版的位置是polls/templates/polls/index.html

{% if latest_poll_list %}
    <ul>
    {% for poll in latest_poll_list %}
        <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

3. 修改檢視函式

from django.http import HttpResponse
from django.template import RequestContext, loader

from polls.models import Poll

def index(request):
    latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = RequestContext(request, {
        'latest_poll_list': latest_poll_list,
    })
    return HttpResponse(template.render(context))

4. 利用快捷方式簡化程式碼

from django.shortcuts import render

from polls.models import Poll

def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    context = {'latest_poll_list': latest_poll_list}
    return render(request, 'polls/index.html', context)

查詢頁面——404頁面的返回

利用try-catch解決404

from django.http import Http404
from django.shortcuts import render

from polls.models import Poll
# ...
def detail(request, poll_id):
    try:
        poll = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404
    return render(request, 'polls/detail.html', {'poll': poll})

此時的polls/detail.html可只填寫內容{{poll}}

利用快捷方式簡化程式碼

from django.shortcuts import render, get_object_or_404

from polls.models import Poll
# ...
def detail(request, poll_id):
    poll = get_object_or_404(Poll, pk=poll_id)
    return render(request, 'polls/detail.html', {'poll': poll})

針對get的函式為get_object_or_404,針對filter的函式為get_list_or_404。
此快捷方式有助於在檢視層不用關心資料層的內容,更好的解耦合。

使用模版系統

#polls/detail.html
<h1>{{ poll.question }}</h1>
<ul>
{% for choice in poll.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

poll.choice_set.all為函式呼叫,返回一個列表。

URL別名的使用

1. 為了簡化URL,消除掉難看的程式碼。

<li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
<li><a href="{% url 'detail' poll.id %}">{{ poll.question }}</a></li>
#既是前面提到的URL別名

2. URL名稱空間

上文所述的別名會造成重名而使Django匹配出錯,因此使用名稱空間

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^polls/', include('polls.urls', namespace="polls")),
    url(r'^admin/', include(admin.site.urls)),
)

相應地,修改

<li><a href="{% url 'polls:detail' poll.id %}">{{ poll.question }}</a></li>

相關文章