Mac Docker 建立第一個Django 應用,Part 3

第三步:Mac Docker建立第一個Django 應用,Part 3

參考原文:Writing your first Django app, part 3
本文Python搭建在 Django Compose + Djang 執行Python需進入web server容器中,請參看[第一步:在Mac構建Django 容器]
翻譯整理:CKhtml

Part3:開發前端

1. 概述

一個View是一個爲特定功能服務的一種網頁,例如在本例中有4個View:前端

  • Question 「index」 page – 展現最新的問題.
  • Question 「detail」 page – 展現一個問題,提供答題表,無答案.
  • Question 「results」 page – 展現一個特定問題的答案.
  • Vote action – 處理針對一個特定問題的投票.

在Djanog中網頁和其餘內容經過View來展現,每一個View至關於一個簡單的Python函數(或方法,在基於類的View中),在URLconfs中作了URL到View的映射。web

2. 編寫更多的View

添加到polls/views.pydjango

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

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

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

添加到polls.urlsapp

from django.conf.urls import url

from . import views

urlpatterns = [
    # ex: /polls/
    url(r'^$', views.index, name='index'),
    # ex: /polls/5/
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

http://127.0.0.1:8000/polls/34/ 爲例, URL之匹配除域名之外的部分,ROOT_URLCONF裏的URL url(r'^polls/', include('polls.urls')), 匹配了 "polls/" 再將剩餘部分 "34/" 發送到‘polls.urls’ URLconf 進一步處理,(?P<question_id>[0-9]+)圓括號用來捕獲值,"?P<question_id>" 用來定義將要匹配到的模式的名字。[0-9]+ 匹配1到多個數字。最後將匹配到的34做爲參數傳給detail方法。函數

3. 寫幾個有用的View

每一個View負責返回一個HttpResponse 對象,或者返回異常如Http404
列出最後5個問題:url

from django.http import HttpResponse

from .models import Question


def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    output = ', '.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

# Leave the rest of the views (detail, results, vote) unchanged

這樣作的缺點時,頁面內容寫在View的代碼裏,若是要改變頁面的樣子,就得修改Python代碼。能夠用模版系統來把Python跟頁面設計區分開來。在setting.py的TEMPLATES設置裏描述了Django如何加載和渲染模版。習慣上Django會在每一個安裝的APP的目錄下查找templates 文件夾。翻譯

建立polls/templates/polls/index.html 寫入:設計

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

修改polls/views.pyrest

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

from .models import Question


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

這段代碼加載polls/templates/polls/index.html 並傳入一個context。這個context是一個字典,將模版的變量名映射爲Pyhon對象。

一個快捷的render() 方法,常見的作法是載入模版,填入上下文,返回一個包含了渲染後之模版的HttpResponse對象。Django提供一個捷徑以下:

重寫polls/views.py

from django.shortcuts import render

from .models import Question


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

4. 報一個404錯誤

修改polls/views.py

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

from .models import Question
# ...
def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, 'polls/detail.html', {'question': question})

建立polls/templates/polls/detail.html

{{ question }}

5. 捷徑:A shortcut: get_object_or_404()

重寫detail方法:

def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})

之因此讓model API 報Http404錯誤而不是ObjectDoesNotExist異常,是由於若是不這樣會形成模型層跟視圖層的耦合。或者說views.py不該該關心模型層面的事情,而應該只專一於如何展現,取到什麼內容就展現什麼。去到的內容是正確的值仍是錯誤信息,應該是model或者controller的事

一樣的get_list_or_404()函數像以前的同樣,除了使用filter()而不是get()。當取回的列表爲空的時候返回404錯誤

5. 使用模版系統

polls/templates/polls/detail.html

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

6. 去掉模版中的URL固定代碼

修改polls/index.html

<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

由於這是緊耦合的作法(當你修改項目的URL的時候,還須要去改動模版),可使用模版標記來去掉模版對特定URL路徑的依賴,改成:

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

這樣的好處是polls.urls模塊中,名爲'detail'的url已經定義好了,根據這個跳轉就了,之後若是要修改指向,只要修改polls.urls就好,例如:

url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),

7. 使用帶命名空間的URL名

若是項目中有多個app 不僅一個app有detail View,如何使用模版標記{% url %} template tag?

polls/urls.py中加入 app_name = 'polls' 變成

from django.conf.urls import url

from . import views

app_name = 'polls'
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

修改polls/templates/polls/index.html

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

這樣Django就知道如何生成動態的超連接指向了,而去要修改app的URL也只須要修改對應app/urls.py ,無需修改模版。因爲模版中每每包含超連接,這樣的好處仍是很大的。

相關文章
相關標籤/搜索