Django快速入門-表單

在上一節的教程中,我們介紹了Django的視圖,並編寫了一個簡單的實例。本小節我們將學習網路投票應用程式,並將側重於簡單的表單處理,以最少代碼代碼量來實現。

編寫一個簡單的表單

讓我們更新 poll detail 範本(“polls/detail.html”) ,從上個教程,在範本 polls/templates/polls/detail.html 包含一個HTML<form>元素:
<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>

簡要介紹:

  • 上面的範本顯示每個問題選擇一個單選按鈕。每個單選按鈕的值相聯問題的選擇編號。每個單選按鈕的名稱是“choice”。這意味著,當有人選擇了其中一個單選按鈕並提交表單,它會發送POST數據choice=#,其中#是被選擇的選擇的ID。這是HTML表單的基本概念。
  • 我們設置表單的動作 {% url 'polls:vote' question.id %}, 以及設置 method="post". 使用 method="post" (相對於 method="get") 是非常重要的,因為提交此表將改變伺服器端數據的行為。當創建一個改變數據伺服器端表單形式,使用 method="post". 這篇文章並不是只針對 Django; 這是一個很好的 Web 開發實踐。
  • forloop.counter表示表單標籤通過多少次迴圈了
  • 因為我們正在創建一個POST形式(可以有修改數據的影響),我們需要擔心跨站點請求偽造。但是也不必擔心,因為Django自帶了保護對抗的一個非常容易使用的系統。總之,這是針對內部URL所有的POST形式應該使用{%csrf_token%}範本標籤。

現在,讓我們創建一個處理提交的數據的一個 Django 視圖。

polls/urls.py檔內容如下:
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'), 

我們還創建了一個虛擬實現 vote() 函數。現在創建一個實用的版本。添加到以下代碼到檔 polls/views.py:

polls/views.py 檔的內容如下:
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers 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):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

此代碼包含還沒有在本教學中涉及幾個東西:

  • request.POST是一個類似於字典的對象,使您可以通過鍵名訪問提交的數據。在這種情況下,request.POST['choice'] 返回被選擇的choice的ID,作為字串。 request.POST的值總是字串。 

    注意:Django還提供 request.GET 以相同的方式訪問 GET數據  – 但我們明確使用 request.POST 在我們的代碼,以確保數據只能通過POST調用修改。

  • 如果POST數據未提供choice,request.POST['choice']將引發KeyError異常。上面的代碼檢查KeyError異常和錯誤消息顯示問題的表單,如果沒有給出 choice

  • 選擇choice計數遞增後,代碼返回 HttpResponse 重定向,而不是一個正常的 HttpResponse。HttpResponseRedirect 需要一個參數:用戶將被重定向到URL(請參閱下麵-我們如何構建在這種情況下的URL)。

    如上Python的注釋所指出的,應該總是在 POST 數據處理成功返回一個HttpResponse重定向。

  • 在本例中我們使用的是 HttpResponseRedirect 構造reverse()函數。此函數有助於避免硬編碼URL在視圖中。這是因為我們想通過控制並指向該視圖的URL模式的可變部分的視圖的名稱。在這種情況下,使用 URLconf 配置使 reverse()調用返回字串如:

    '/polls/3/results/'

    其中3是question.id的值。然後,這個重定向的URL將調用“results”視圖中顯示的最後一頁。

現在訪問網址:http://127.0.0.1:8000/polls/1/ 得到結果如下所示:

當有人在一個問題投票後,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/results.html (polls/templates/polls/results.html)範本:

<h2>{{ question.question_text }}</h2>

<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/ 並表決的問題。應該會被每次投票時看到更新結果頁。如果您提交表單不選擇一個選項,應該看到錯誤消息。
選擇選項,提交後顯示如下結果:

使用通用視圖:更少的代碼更好

修改URL配置

首先,打開 polls/urls.py 並修改如下:

from django.conf.urls import url

from . import views

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

請注意,第二和第三模式的正則運算式匹配的模式名稱已經從<question_id>改變為<to>。

修改視圖

接下來,我們要刪除舊的 index, detail, 和 results 視圖使用Django通用視圖代替。要做到這一點,打開 polls/views.py 檔並修改它如下:

from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.core.urlresolvers 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):
    ... # same as above

剩下的你自己發揮了,包教不包會,請參考:https://docs.djangoproject.com/en/1.9/intro/tutorial04/

代碼下載:http://pan.baidu.com/s/1bt4efW
上一篇: Django快速入門-視圖 下一篇:無