Django學習3:views,urls
Django學習3
views是一個面向public的介面,它是專案中提供特定功能的頁面。在Django中web的頁面以及一些其他的內容都是通過view來表達,Django利用url的檢查,拆分來選擇views來顯示。教程中的polls的專案需要如下幾個views:
- Question索引:用來顯示最近釋出的Question。
- Question詳情:顯示Question的內容以及可以投票的表單。
- Question結果:顯示當前的Question的投票結果。
- 投票動作:為Question投票。
step1:view練習
我們之前已經在polls/views.py中建立了一個index的views,現在繼續新增如下的views:
#這裡%s是python的新特性,甚至可以用元組來在一個地方插入數個string
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)
這裡需要注意的就是%s的用法,具體在stackoverflow上 有解答。 完成了上述工作後就需要讓這些views可以被使用,在polls/urls.py中可以增加如下程式碼讓這些views能根據request被訪問:
urlpatterns = [
# ex: /polls/
path('', views.index, name='index'),
# ex: /polls/5/
path('<int:question_id>/', views.detail, name='detail'),
# ex: /polls/5/results/
path('<int:question_id>/results/', views.results, name='results'),
# ex: /polls/5/vote/
path('<int:question_id>/vote/', views.vote, name='vote'),
]
這樣比如輸入”127.0.0.1:8000/5”就會進入一個頁面顯示“You’re looking at question 5.”。在這< int:question_id >中< int:表示int型別來匹配question_id >表示定義被匹配的url字串的名字。
疑問
這樣我有一個疑問就是如何確定到底有沒有標號5的Question,這個問題應該會在後面解答。
step2:正式進入views的應用
在經過了上述的練習就大概知道了views的使用流程,下面可以針對polls這個應用寫一些有意義的頁面。 在此之前,需要知道的是view所做的工作無非是:一,返回一個HttpResponse;二,返回錯誤資訊。並且view可以讀取資料庫資訊,使用python模板,生成pdf等等功能,所以Django需要的只是HttpResponse,或者是錯誤資訊。 接下來我們就在polls/views.py中重寫index頁面的view讓它可以顯示最新的5個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)
這裡”’,’ . join([])“就是用,隔開list中的元素並組成字串。 這樣子完成後,輸入/polls頁面就會發現出現了最近建立的5個Question。但是這樣用python寫的頁面設計並不是特別方便和美觀,所以就要用到Django的template system。 那麼首先需要在polls資料夾下建立一個名為templates的目錄,然後再在templates層建立一個polls目錄,而後在再polls下建立一個index.html,所以最終路徑就是polls/templates/polls/index.html,這樣保證了名稱空間的獨立性,保證和其他app有重名template也沒有關係,並且由於內部template,可以直接用polls/index.html來使用。 而後在此檔案中輸入如下程式碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% 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 %}
</body>
</html>
之後在polls/views.py中修改index的view程式碼:
from django.template import loader
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))
#也可以:return render(request, 'polls/index.html', context)
上述程式碼就是在view中載入了polls/index.html的程式碼並且將一個context傳遞給index.html而這個context就是一個字典,來表名在python中出現的object。
step3:a 404 error
那麼使用404這個方法就可以解決我上面所說不能判斷到底有沒有這個請求的投票的問題。 在detail中可以去查詢資料庫,如果沒有match到的記錄,就給出404的介面,具體程式碼如下:
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})
#It can also work
'''
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
'''
/polls/templates/polls/detail.html頁面程式碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>detail</title>
</head>
<body>
{{ question }}
</body>
</html>
這樣每次都會去資料庫檢查是否有這個id的資料記錄,利用try except來完成避免訪問空的頁面。在detail.html中可以簡單的寫一句{{question}}
就可以檢視結果。
疑問
問什麼可以直接使用{{question}}
就可以顯示其中的內容,但是好像{{ question.question_text}}
也可以顯示。
step4:使用template system
由於template的存在,所以就可以直接呼叫Question關聯的choice,polls/templates/polls/detail.html程式碼如下:
<body>
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>
{{ choice.choice_text }}
</li>
{% endfor %}
</ul>
</body>
如上程式碼所示,tmeplate system利用”.”來引用屬性,它會先去尋找object的字典樹然後再去尋找它的屬性,然後再去尋找它的索引。
step5:去除template中的hardcoded urls
在之前的index中我們使用了< a href = …的標籤,其中我們是直接用”/polls/{ question.id}}/”來直接規定了link的指向,但是這樣並不好,不方便修改。 我們可以將其改成如下形式:
<a href="{% url 'detail' question.id %}">{{ question.question_text }}</a>
這時候之前在urls.py中定義的name就有用了,以後如果想要改成如/polls/specifics/12/就可以直接在path中改成:
path('specifics/<int:question_id>/', views.detail, name='detail'),
step6:namespacing
在真正的專案中通常一個專案有多個app,這時候如果多個app都有detail view怎麼辦呢,這樣之前所用的{% url %}
就分不清取用那個detail了。
所以在polls/urls.py中最頂上增加一條
app_name = 'polls'
然後將polls/templates/polls/index.html中的
<a href = "{% url 'detail' question.id %}>"
改成
< a href = "{% url 'pollls:detail' question.id" %}>