<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] 這一節我們將繼續編寫投票應用,并專注于簡單的表單處理,以及精簡我們的代碼。 <br /> ## **一、表單form** 為了接收用戶的投票選擇,我們需要在前端頁面顯示一個投票界面。讓我們重寫先前的`polls/detail.html`文件,代碼如下: ~~~ <h1>{{ question.question_text }}</h1> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="{% url 'polls:vote' question.id %}" method="post"> {% csrf_token %} {% for choice in question.choice_set.all %} <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"> <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br> {% endfor %} <input type="submit" value="Vote"> </form> ~~~ 簡要說明: * 上面的模板顯示一系列單選按鈕,按鈕的值是選項的ID,按鈕的名字是字符串"choice"。這意味著,當你選擇了其中某個按鈕,并提交表單,一個包含數據`choice=#`的POST請求將被發送到指定的url,`#`是被選擇的選項的ID。這就是HTML表單的基本概念。 * 如果你有一定的前端開發基礎,那么form標簽的action屬性和method屬性你應該很清楚它們的含義,action表示你要發送的目的url,method表示提交數據的方式,一般分post和get。 * `forloop.counter`是Django模板系統專門提供的一個變量,用來表示你當前循環的次數,一般用來給循環項目添加有序數標。 * 由于我們發送了一個POST請求,就必須考慮一個跨站請求偽造的安全問題,簡稱CSRF(具體含義請百度)。Django為你提供了一個簡單的方法來避免這個困擾,那就是在form表單內添加一條`{% csrf_token %}`標簽,標簽名不可更改,固定格式,位置任意,只要是在form表單內。這個方法對form表單的提交方式方便好使,但如果是用ajax的方式提交數據,那么就不能用這個方法了。 現在,讓我們創建一個處理提交過來的數據的視圖。前面我們已經寫了一個“占坑”的vote視圖的url(polls/urls.py): ~~~ path('<int:question_id>/vote/', views.vote, name='vote'), ~~~ 以及“占坑”的vote視圖函數(polls/views.py),我們把坑填起來: ~~~ from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.urls import reverse from .models import Choice, Question # ... def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) ~~~ 有些新的東西,我們要解釋一下: * `request.POST`是一個類似字典的對象,允許你通過鍵名訪問提交的數據。本例中,`request.POST[’choice’]`返回被選擇選項的ID,并且值的類型永遠是string字符串,哪怕它看起來像數字!同樣的,你也可以用類似的手段獲取GET請求發送過來的數據,一個道理。 * `request.POST[’choice’]`有可能觸發一個KeyError異常,如果你的POST數據里沒有提供choice鍵值,在這種情況下,上面的代碼會返回表單頁面并給出錯誤提示。 * 在選擇計數器加一后,返回的是一個`HttpResponseRedirect`而不是先前我們常用的`HttpResponse`。`HttpResponseRedirect`需要一個參數:重定向的URL。這里有一個建議,當你成功處理POST數據后,應當保持一個良好的習慣,始終返回一個`HttpResponseRedirect`。這不僅僅是對Django而言,它是一個良好的WEB開發習慣。 * 我們在上面`HttpResponseRedirect`的構造器中使用了一個`reverse()`函數。它能幫助我們避免在視圖函數中硬編碼URL。它首先需要一個我們在URLconf中指定的name,然后是傳遞的數據。例如`'/polls/3/results/'`,其中的3是某個`question.id`的值。重定向后將進入`polls:results`對應的視圖,并將`question.id`傳遞給它。白話來講,就是把活扔給另外一個路由對應的視圖去干。 當有人對某個問題投票后,vote()視圖重定向到了問卷的結果顯示頁面。下面我們來寫這個處理結果頁面的視圖(polls/views.py): ~~~ from django.shortcuts import get_object_or_404, render def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question}) ~~~ 同樣,還需要寫個模板`polls/templates/polls/results.html`。(路由、視圖、模板、模型!都是這個套路....) ~~~ <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> <a href="{% url 'polls:detail' question.id %}">Vote again?</a> ~~~ 現在你可以到瀏覽器中訪問`/polls/1/`了,投票吧。你會看到一個結果頁面,每投一次,它的內容就更新一次。如果你提交的時候沒有選擇項目,則會得到一個錯誤提示。 如果你在前面漏掉了一部分操作沒做,比如沒有創建choice選項對象,那么可以按下面的操作,補充一下: ~~~ F:\Django_course\mysite>python manage.py shell Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from polls.models import Question >>> q = Question.objects.get(pk=1) >>> q.choice_set.create(choice_text='Not much', votes=0) <Choice: Choice object> >>> q.choice_set.create(choice_text='The sky', votes=0) <Choice: Choice object> >>> q.choice_set.create(choice_text='Just hacking again', votes=0) <Choice: Choice object> ~~~ <br /> ## **二、 使用通用視圖:減少重復代碼** 上面的detail、index和results視圖的代碼非常相似,有點冗余,這是一個程序猿不能忍受的。他們都具有類似的業務邏輯,實現類似的功能:通過從URL傳遞過來的參數去數據庫查詢數據,加載一個模板,利用剛才的數據渲染模板,返回這個模板。由于這個過程是如此的常見,Django很善解人意的幫你想辦法偷懶,于是它提供了一種快捷方式,名為“通用視圖”。 現在,讓我們來試試看將原來的代碼改為使用通用視圖的方式,整個過程分三步走: * 修改URLconf設置 * 刪除一些舊的無用的視圖 * 采用基于類視圖的新視圖 **PS:為什么本教程的代碼來回改動這么頻繁?** <br /> 答:通常在寫一個Django的app時,我們一開始就要決定使用通用視圖還是不用,而不是等到代碼寫到一半了才重構你的代碼成通用視圖。但是本教程為了讓你清晰的理解視圖的內涵,“故意”走了一條比較曲折的路,因為我們的哲學是`在你使用計算器之前你得先知道基本的數學知識`。 <br /> Django的視圖類型可以分為函數視圖和類視圖,也就是FBV和CBV,兩者各有優缺點,CBV不一定就高大上。大多數場景下,函數視圖更簡單易懂,代碼量更少。但是在需要繼承、封裝某些視圖的時候,CBV就能發揮優勢。 <br /> 這節介紹的通用視圖其實就是Django內置的一些類視圖,可以拿來直接使用。但非常簡單,只適用于一些簡單場景,如果業務邏輯比較復雜,依然需要改造。 <br /> ### 1.**改良URLconf** 打開`polls/urls.py`文件,將其修改成下面的樣子: ~~~ from django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.IndexView.as_view(), name='index'), path('<int:pk>/', views.DetailView.as_view(), name='detail'), path('<int:pk>/results/', views.ResultsView.as_view(), name='results'), path('<int:question_id>/vote/', views.vote, name='vote'), ] ~~~ 請注意:在上面的的第二、三條目中將原來的`<question_id>`修改成了`<pk>`. <br /> ### 2.**修改視圖** 接下來,打開`polls/views.py`文件,刪掉index、detail和results視圖,替換成Django的通用視圖,如下所示: ~~~ from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.urls import reverse from django.views import generic from .models import Choice, Question class IndexView(generic.ListView): template_name = 'polls/index.html' context_object_name = 'latest_question_list' def get_queryset(self): """Return the last five published questions.""" return Question.objects.order_by('-pub_date')[:5] class DetailView(generic.DetailView): model = Question template_name = 'polls/detail.html' class ResultsView(generic.DetailView): model = Question template_name = 'polls/results.html' def vote(request, question_id): ... # 同前面的一樣,不需要修改 ~~~ 在這里,我們使用了兩種通用視圖`ListView`和`DetailView`(它們是作為父類被繼承的)。這兩者分別代表“顯示一個對象的列表”和“顯示特定類型對象的詳細頁面”的抽象概念。 * 每一種通用視圖都需要知道它要作用在哪個模型上,這通過model屬性提供。 * `DetailView`需要從url捕獲到的稱為"pk"的主鍵值,因此我們在url文件中將2和3條目的`<question_id>`修改成了`<pk>`。 <br /> 默認情況下,`DetailView`通用視圖使用一個稱作`<app name>/<model name>_detail.html`的模板。在本例中,實際使用的是`polls/detail.html`。`template_name`屬性就是用來指定這個模板名的,用于代替自動生成的默認模板名。(一定要仔細觀察上面的代碼,對號入座,注意細節。)同樣的,在results列表視圖中,指定`template_name`為`'polls/results.html'`,這樣就確保了雖然resulst視圖和detail視圖同樣繼承了DetailView類,使用了同樣的model:Qeustion,但它們依然會顯示不同的頁面。(模板不同嘛!so easy!) <br /> 類似的,ListView通用視圖使用一個默認模板稱為`<app name>/<model name>_list.html`。我們也使用`template_name`這個變量來告訴ListView使用我們已經存在的`"polls/index.html"`模板,而不是使用它自己默認的那個。 <br /> 在教程的前面部分,我們給模板提供了一個包含`question`和`latest_question_list`的上下文變量。而對于DetailView,question變量會被自動提供,因為我們使用了Django的模型(Question),Django會智能的選擇合適的上下文變量。然而,對于ListView,自動生成的上下文變量是`question_list`。為了覆蓋它,我們提供了`context_object_name`屬性,指定說我們希望使用`latest_question_list`而不是`question_list`。 <br /> 現在可以運行開發服務器,然后試試基于類視圖的應用程序了,效果和前面的函數視圖是一樣的。 <br /> 類視圖是Django比較高級的一種用法,初學可能不太好理解,沒關系,我們先有個印象。更多內容可以學習博客:https://www.liujiangblog.com/blog/37/ <br /> 簡要分析: 1. 類視圖相比函數視圖具有類的特性,可封裝可繼承,利于代碼重用 2. 通用視圖是類視圖的一種 3. 通用視圖的代碼雖然少了,但學習成本高了 4. 我們在享受便利的同時,要記住更多通用視圖的用法和規則,有得有失 5. 其實我們完全可以自己編寫新的通用視圖,自己定規則定規矩,不必使用Django提供的,這相當于造輪子 6. 不要沉迷于類視圖的強大。在編程的世界其實有句話也很適合:一切的饋贈在初始就定好了代價。獲得越多,失去也多,這里方便了,那里就復雜了。
                  <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>

                              哎呀哎呀视频在线观看