續上一篇,這一篇 著重于創建公共接口——“視圖”
第三部分——3、視圖和模板
- 1、概述
- 2、編寫更多視圖
- 原理——django依次訪問了什么文件
- 3、寫一個真正有用的視圖
- 一個快捷函數 render() render——渲染
- 4、拋出404錯誤
- 一個快捷函數 get_object_or_404()
- 5、使用模板系統
- 6、去除模板中的硬編碼URL
- 7、為URL名稱添加命名空間
1、概述
- Django中視圖——一類具有相同功能和模板的網頁的集合
- 網頁和其他內容由視圖派生而來。
- 視圖是一個python函數or方法
- 根據用戶請求的URL(域名之后的部分)來選擇使用哪個視圖
- 將URL與視圖關聯起來——URLconfs(將URL映射到視圖)來配置
2、編寫更多視圖
在 polls/views 增加
def detail(request,question_id):return HttpResponse("You're loooking 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/urls 模塊中
urlpatterns=[path("",views.index,name="index"),path("<int:question_id>/",views.detail,name="detail"),path("<int:question_id>/results/",views.results,name="results"),path("<int:question_id>/vote/",views.vote,name="vote"),
]
接下來訪問“/polls/34/”它將運行detail()函數,顯示為:
同理訪問“/polls/2/results/”,或者訪問“/polls/2/vote/”:將看到:
原理——django依次訪問了什么文件
- 訪問根urls.py文件,即ROOT_URLCONF,按順序遍歷這些模式,匹配path(“polls/”,include(“polls.urls”)),并將剩余的文本發送給polls.urls
- Django 會匹配 path(‘int:question_id/’, views.detail, name=‘detail’),其中 ‘int:question_id/’ 表示將URL路徑的這一部分解析為整數,并作為 question_id 參數傳遞給 detail 視圖函數。
- 在polls/views,detail 函數接收兩個參數:request 和 question_id。當你訪問 /polls/34/ 時,question_id 的值為 34,因此視圖函數會返回包含 “You’re looking at question 34.” 的響應。
總結:
1、Django加載項目的URL配置:mysite/urls.py。
2、匹配到包含的應用URL配置:polls/urls.py。
3、解析URL路徑參數并調用相應視圖函數:將 question_id 解析為 34,并調用 detail 視圖函數。
4、視圖函數處理請求并返回響應:detail 函數生成并返回響應。
3、寫一個真正有用的視圖
視圖必須做的只有兩件事:返回一個包含被請求頁面的HttpResponse對象。或者拋出一個異常。
視圖還可以做什么?視圖可以從數據庫讀記錄,可以使用一個模板引擎,,可以生成一個pdf文件,可以輸出一個xml,可以創建一個zip文件,可以做任何你想做的事情。
接下來修改polls/views/index()函數,顯示最近的五個問題
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)
- 這里有一個問題,頁面的代碼寫死在了視圖函數里,這里解釋一下什么叫“寫死”,以及它的弊端
當我們說頁面的設計“寫死”在視圖函數里時,意思是視圖函數中包含了生成頁面內容的具體代碼。如果你想修改頁面的外觀或布局,就必須直接編輯這些視圖函數。這種做法的問題在于:
1、難以維護和更新:每次需要修改頁面的外觀或布局時,都必須直接更改視圖函數中的代碼,可能導致代碼變得復雜和難以維護。
2、代碼與內容耦合:視圖函數不僅負責處理請求邏輯,還負責生成HTML內容,使得業務邏輯和頁面設計耦合在一起。
3、復用性差:如果不同的視圖函數需要共享相同的HTML結構或樣式,每個視圖函數都必須重復相同的HTML代碼,導致代碼重復和不易復用。
所以要使用Django的模板系統,只需要創建一個視圖,就可以將頁面的設計從代碼里分離出來
首先,創建polls/templates目錄。Django會在這個目錄里查找模板文件
接著創建templates/polls/index.html
- 避免模板文件名稱沖突,我們應該將模板文件放在與應用同名的子文件夾中。這樣做的好處是,如果你有多個應用程序,它們可以使用相同名稱的模板文件而不會互相沖突
- 命名空間:為了幫助Django區分不同應用的模板,我們將模板文件放在與應用同名的子文件夾中。這就是所謂的命名空間。例如,對于 polls 應用,我們應該在 polls/templates 目錄下再創建一個 polls 子目錄。
在index.html文件中:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Polls Index</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>
<ul>:表示無序列表(unordered list)。通常用于列出項目,每個項目由 <li>(列表項)標簽表示。<li>:表示列表中的項目(list item)。在無序列表 <ul> 或有序列表 <ol> 中使用。<a>:表示超鏈接(anchor)。用于創建鏈接,可以導航到其他頁面或資源。href 屬性指定鏈接目標。<p>:表示段落(paragraph)。用于定義文檔中的段落,瀏覽器會自動在段落前后添加一些空白,以便段落與其他內容分開。{{ }}:Django模板語法,用于輸出變量的值。例如,{{ question.id }} 輸出問題的ID,{{ question.question_text }} 輸出問題的文本。{% %}:Django模板標簽,用于執行邏輯語句或控制流。例如,{% if latest_question_list %} 檢查 latest_question_list 是否有數據,{% for question in latest_question_list %} 循環遍歷 latest_question_list 中的每個問題,{% endif %} 結束 if 語句,{% endfor %} 結束 for 循環。
接下來更新polls/views.py中的Index視圖
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))#模板渲染
一個快捷函數 render() render——渲染
載入模板,填充上下文,再返回由它生成的HttpResponse對象
這是一個非常常見的操作流程,于是Django提供了一個快捷函數,我們用它來重寫index()視圖
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)
此時,就不再需要導入loader和HttpResponse啦
4、拋出404錯誤
接下來我們來處理 投票詳情頁面——它會顯示指定投票的問題標題
from django.http import Http404
def detail(request,question_id):try:question=Question.objects.get(pk=question_id)except Question.DoesNotExist:#當指定問題ID所對應的問題不存在,這個視圖就會拋出一個Http404錯誤raise Http404("Question does not exist")return render(request,"polls/detail.html",{"question":question})
一個快捷函數 get_object_or_404()
嘗試用get函數來獲取一個對象,如果不存在就拋出一個404錯誤
這是一個普遍的流程,Django也提供了一個快捷的函數,下面是修改的detail代碼
from django.shortcuts import get_object_or_404
def detail(request,question_id):question=get_object_or_404(Question,pk=question_id)return render(request,"polls/detail.html",{"question":question})
使用輔助函數 get_object_or_404,而不是自己捕獲ObjectDoesNotExist異常?為什么模型API不直接拋出ObjectDoesNotExist,而是拋出Http404呢?
這樣會增加 模型層 和 視圖層 的 耦合性。但是指導Django設計的最重要的思想之一就是要 保證松散耦合。yi==一些受控的耦合會被包含在django.shortcuts模塊中。
5、使用模板系統
在 polls/detail.html 中:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Polls Details</title>
</head>
<body><h1>{{question.question_text}}</h1><ul>{% for choice in question.choice_set.all %}<li>{{ choice.choice_text }}</li>{% endfor %}</ul>
</body>
</html>
6、去除模板中的硬編碼URL
在polls/index.html 中編寫投票鏈接時,鏈接是硬編碼
<li><a href="/polls/{{question.id}}/">{{question.question_text}}</a></li>
這種 硬編碼、強耦合的方法的問題在于,在具有大量模板的項目中更改url變得更有挑戰性。還記得在polls/urls模塊中,path()函數中定義了name參數,你可以通過使用
{% url %} 模板標簽來消除對url配置中定義的特定的URL路徑的依賴
將其修改為:
<li><a href="{% url"detail"question.id %}">{{question.question_text}}</a></li>
回憶一下在polls.urls中:
如果你想改變投票詳情頁面的url 比如想改成polls/specifics/12/,你不需要在模板里(包括其他模板),只要在polls/urls.py里稍微修改一下就行:
path("specifics/<int:question_id>/",views.detail,name="detail"),
此時訪問http://127.0.0.1:8000/polls/specifics/2/將看到
7、為URL名稱添加命名空間
本教程中只有一個應用:polls,在實際中可能會有好幾十個應用。那么如果兩個應用出現重名的url時,Django怎么分辨呢?比如,polls應用有detail視圖,另一個博客應用也有detail視圖,Django如何知道 {% url %} 到底對應的是哪個應用呢,需要在兩個地方做出聲明:
1、在polls.urls中設置命名空間:
2、在模板標簽處(index.html/a href)添加聲明