<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] ## **一、概述** Django 中的視圖的概念是一類具有相同功能和模板的網頁的集合。一個視圖通常對應一個頁面,提供特定的功能,使用特定的模板。例如:在一個博客應用中,你可能會看到下列視圖: * 博客主頁:顯示最新發布的一些內容 * 每篇博客的詳細頁面:顯示博客的詳細內容 * 基于年的博客頁面:顯示指定年內的所有博客文章 * 基于月的博客頁面:顯示指定月內的所有博客文章 * 基于天的博客頁面:顯示指定日內的所有博客文章 * 發布評論:處理針對某篇博客發布的評論 在我們的投票應用中,我們將建立下面的視圖: * 問卷“index”頁:顯示最新的一些問卷 * 問卷“detail”頁面:顯示一個問卷的詳細文本內容,沒有調查結果但是有一個投票或調查表單。 * 問卷“results”頁面:顯示某個問卷的投票或調查結果。 * 投票動作頁面:處理針對某個問卷的某個選項的投票動作。 <br /> 在Django中,網頁和其它的一些內容都是通過視圖來處理的。視圖其實就是一個簡單的Python函數(在基于類的視圖中稱為方法)。Django通過對比請求的URL地址來選擇對應的視圖,也就是路由。 <br /> 在你上網的過程中,很可能看見過像這樣的丑陋的URL: "ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B" 。別擔心,Django 里的 URL規則要比這優雅的多!比如:`/newsarchive/<year>/<month>/`。 為了將 URL 和視圖關聯起來,Django 使用`URLconfs`來配置路由。 <br /> ## **二、編寫視圖** 下面,打開`polls/views.py`文件,輸入下列代碼: ~~~ # 注意函數的參數 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/urls.py`文件中加入下面的路由,將其映射到我們上面新增的視圖。 ~~~ from django.urls import path from . import views urlpatterns = [ # 例如: /polls/ path('', views.index, name='index'), # 例如: /polls/5/ path('<int:question_id>/', views.detail, name='detail'), # 例如: /polls/5/results/ path('<int:question_id>/results/', views.results, name='results'), # 例如: /polls/5/vote/ path('<int:question_id>/vote/', views.vote, name='vote'), ] ~~~ 現在去瀏覽器中訪問`/polls/34/`(注意:這里省略了域名。另外,使用了二級路由后,url中都要添加字符串`polls`前綴,參考前面的章節),它將調用`detail()`函數,然后在頁面中顯示你在url里提供的ID。訪問`/polls/34/results/`和`/polls/34/vote/`,將分別顯示預定義的偽結果和投票頁面。(PS:這里就不貼圖了,請大家務必自己動手測試,多實踐。切記不要輸入錯誤!) <br /> 上面訪問的路由過程如下:當有人訪問`/polls/34/`地址時,Django將首先加載`mysite.urls`模塊,因為它是settings文件里設置的根URL配置文件。在該文件里,Django發現了`urlpatterns`變量,于是在其內按順序進行匹配。當它匹配上了`polls/`,就裁去url中匹配的文本`polls/`,然后將剩下的文本“`34/`”,傳遞給`polls.urls`進行下一步的處理。在`polls.urls`中,又匹配到了`<int:question_id>/`,最終結果就是調用該模式對應的detail視圖,也就是下面的函數: ~~~ detail(request=<HttpRequest object>, question_id=34) ~~~ 函數中的`question_id=’34’`參數,是由`<int:question_id>/`而來。使用尖括號“捕獲”這部分 URL,且以關鍵字參數的形式發送給視圖函數。上述字符串的`question_id`部分定義了將被用于區分匹配模式的變量名,而`int`則是一個轉換器決定了應該以什么變量類型匹配這部分的 URL 路徑。 不要書寫類似下面的較為愚蠢的包含`.html`的模式,它顯然是沒必要,不夠簡練的: ~~~ path('polls/latest.html', views.index), ~~~ <br /> ## **三、編寫能實際干點活的視圖** 每個視圖至少做兩件事之一:返回一個包含請求頁面的HttpResponse對象或者彈出一個類似Http404的異常。其它的則隨你便,你愛干嘛干嘛。 <br /> 下面是一個新的index視圖,用于替代先前無用的index,它會根據發布日期顯示最近的5個投票問卷。 ~~~ 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) # 省略了那些沒改動過的視圖(detail, results, vote) ~~~ **這里有個非常重要的問題:在當前視圖中的HTML頁面是硬編碼的。** 如果你想改變頁面的顯示內容,就必須修改這里的Python代碼。為了解決這個問題,需要使用Django提供的模板系統,解耦視圖和模板之間的硬連接。 <br /> 首先,在`polls`目錄下創建一個新的`templates`目錄,Django會在它里面查找模板文件。 <br /> 項目`settings.py`文件中的`TEMPLATES`配置項描述了 Django 如何載入和渲染模板。默認的設置文件設置了`DjangoTemplates`后端作為模板引擎,并將`APP_DIRS`設置成了 True。這一選項將會讓`DjangoTemplates`在每個`INSTALLED_APPS`文件夾中尋找 "`templates`" 子目錄。 <br /> 在剛才創建的`templates`目錄中,再創建一個新的子目錄名叫`polls`,進入該子目錄,創建一個新的HTML文件`index.html`。換句話說,你的模板文件應該是`polls/templates/polls/index.html`。因為 Django 會尋找到對應的`app_directories`,所以你只需要使用`polls/index.html`就可以引用到這一模板了。 <br /> **模板命名空間:** 你也許會想,為什么不把模板文件直接放在`polls/templates`目錄下,而是費勁的再建個子目錄polls呢?設想這么個情況,有另外一個app,它也有一個名叫`index.html`的文件,當Django在搜索模板時,有可能就找到它,然后退出搜索,這就命中了錯誤的目標,不是我們想要的結果。解決這個問題的最好辦法就是在templates目錄下再建立一個與app同名的子目錄,將自己所屬的模板都放到里面,從而達到獨立命名空間的作用,不會再出現引用錯誤。 現在,將下列代碼寫入文件`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 %} ~~~ 為了讓教程看起來不那么長,所有的模板文件都只寫出了核心代碼。在你自己創建的項目中,你應該使用 完整的 HTML 文檔,比如: ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>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> ~~~ 同時,修改視圖文件`polls/views.py`,讓新的`index.html`文件生效: ~~~ 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/index.html`文件,并傳遞給它一個參數。這個參數是一個字典,包含了模板變量名和Python對象之間的映射關系。 <br /> 在瀏覽器中通過訪問`/polls/`,你可以看到一個列表,包含`“What’s up”`的問卷,以及連接到其對應詳細內容頁面的鏈接點。 <br /> 注意:如果你顯示的是`No polls are available.`說明你前面沒有添加Questions對象。前面的大量手動API操作你沒有做。沒關系,我們在admin中追加對象就可以。 <br /> **快捷方式:render()** <br /> 在實際運用中,加載模板、傳遞參數,返回HttpResponse對象是一整套再常見不過的操作了,為了節省力氣,Django提供了一個快捷方式:render函數,一步到位! 將`polls/views.py`中的index修改成下面的代碼: ~~~ 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) ~~~ 注意,我們不再需要導入`loader`,而是從`django.shortcuts`導入了render。 <br /> render()函數的第一個位置參數是請求對象(就是view函數的第一個參數),這個參數是固定寫法,不需要變動。第二個位置參數是模板文件。還可以有一個可選的第三參數,一個字典,包含需要傳遞給模板的數據。最后render函數返回一個經過字典數據渲染過的模板封裝而成的HttpResponse對象。 <br /> ## **四、返回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}) ~~~ 這里有個新知識點,如果請求的問卷ID不存在,那么會彈出一個Http404錯誤。 如果你想試試上面這段代碼是否正常工作的話,你可以新建`polls/detail.html`文件,暫時寫入下面的代碼: ~~~ {{ question }} ~~~ <br /> **快捷方式:get_object_or_404()** 就像render函數一樣,Django同樣為你提供了一個偷懶的方式,替代上面的多行代碼,那就是`get_object_or_404()`方法,參考下面的代碼: polls/views.py ~~~ from django.shortcuts import get_object_or_404, render from .models import Question # ... def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question}) ~~~ 別說我沒提醒你,和render一樣,也需要從Django內置的快捷方式模塊中導出`get_object_or_404()`! <br /> `get_object_or_404()`方法將一個Django模型作為第一個位置參數,后面可以跟上任意數量的關鍵字參數,如果對象不存在則彈出Http404錯誤。 <br /> 同樣,還有一個`get_list_or_404()`方法,和上面的`get_object_or_404()`類似,只不過是用來替代`filter()`函數,當查詢列表為空時彈出404錯誤。(filter是模型API中用來過濾查詢結果的函數,它的結果是一個列表集。而get則是查詢一個結果的方法,和filter是一個和多個的區別!) <br /> 為什么我們使用輔助函數`get_object_or_404()`而不是自己捕獲`ObjectDoesNotExist`異常呢?還有,為什么模型 API 不直接拋出`ObjectDoesNotExist`而是拋出`Http404`呢?因為這樣做會增加模型層和視圖層的耦合性。指導 Django 設計的最重要的思想之一就是要保證松散耦合。一些受控的耦合將會被包含在`django.shortcuts`模塊中。 <br /> ## **五、 使用模板系統** 回過頭去看看我們的 detail視圖。它向模板傳遞了上下文變量 question 。下面是 polls/detail.html 模板里正式的代碼: ~~~ <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul> ~~~ <br /> 在模板系統中圓點`.`是萬能的魔法師,你可以用它訪問對象的屬性。在例子`{{ question.question_text }}`中,Django首先會在question對象中嘗試查找一個字典,如果失敗,則嘗試查找屬性,如果再失敗,則嘗試作為列表的索引進行查詢。 <br /> 在`{% for %}`循環中的方法調用——`question.choice_set.all`其實就是Python的代碼`question.choice_set.all()`,它將返回一組可迭代的`Choice`對象,并用在`{% for %}`標簽中。 <br /> 這里我們對Django模板語言有個簡單的印象就好,更深入的介紹放在后面。 <br /> ## **六、刪除模板中硬編碼的URLs** 在`polls/index.html`文件中,還有一部分硬編碼存在,也就是`href`里的“/polls/”部分: ~~~ <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> ~~~ 它對于代碼修改非常不利。設想如果你在urls.py文件里修改了路由表達式,那么你所有的模板中對這個url的引用都需要修改,這是無法接受的! 我們前面給urls定義了一個name別名,可以用它來解決這個問題。具體代碼如下: ~~~ <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li> ~~~ Django會在`polls.urls`文件中查找`name='detail'`的路由,具體的就是下面這行: ~~~ path('<int:question_id>/', views.detail, name='detail'), ~~~ 舉個栗子,如果你想將polls的detail視圖的URL更換為`polls/specifics/12/`,那么你不需要在模板中重新修改url地址了,僅僅只需要在`polls/urls.py`文件中,將對應的正則表達式改成下面這樣的就行了,所有模板中對它的引用都會自動修改成新的鏈接: ~~~ # 添加新的單詞'specifics' path('specifics/<int:question_id>/', views.detail, name='detail'), ~~~ <br /> ## **七、URL names的命名空間** 本教程例子中,只有一個app,也就是polls,但是在現實中很顯然會有5個、10個、更多的app同時存在一個項目中。Django是如何區分這些app之間的URL name呢?舉個例子,`polls`應用有`detail`視圖,可能另一個博客應用也有同名的視圖。Django 如何知道`{% url %}`標簽到底對應哪一個應用的 URL 呢? <br /> **答案是使用URLconf的命名空間。** 可以在polls/urls.py文件的開頭部分,添加一個`app_name`的變量來指定該應用的命名空間: ~~~ from django.urls import path from . import views app_name = 'polls' # 重點是這一行 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/templates/polls/index.html`中的 ~~~ <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li> ~~~ 修改為: ~~~ <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> ~~~ **注意引用方法是冒號,不是圓點也不是斜杠!**
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看