4.1 Create a simple form
parent
624f61a563
commit
e0267685cc
|
@ -246,4 +246,83 @@ Consider `index.html` will be reused numerous times, 去耦合is necessary.
|
||||||
在根 URLconf 中添加命名空间 (namespace)
|
在根 URLconf 中添加命名空间 (namespace)
|
||||||
|
|
||||||
1. Add `app_name = 'polls'` for namespace in `poll.urls.py`
|
1. Add `app_name = 'polls'` for namespace in `poll.urls.py`
|
||||||
2. Change `detail` in `index.html` to `polls:detail`
|
2. Change `detail` in `index.html` to `polls:detail`
|
||||||
|
|
||||||
|
## Part 4. Form
|
||||||
|
|
||||||
|
### 4.1 编写一个简单的表单
|
||||||
|
|
||||||
|
Edit `polls/templates/polls/detail.html` so it contain **`HTML<form>`** elements:
|
||||||
|
|
||||||
|
```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>
|
||||||
|
```
|
||||||
|
|
||||||
|
Explain:
|
||||||
|
|
||||||
|
* 当有人选择一个单选按钮并提交表单提交时,它将发送一个 POST 数据 choice=# ,其中# 为选择的 Choice 的 ID。这是 HTML 表单的基本概念。
|
||||||
|
* 我们设置表单的 action 为 {% url 'polls:vote' question.id %} ,并设置 method="post" 。使用 method="post"``(与其相对的是 ``method="get"`)是非常重要的,因为这个提交表单的行为会改变服务器端的数据。 **无论何时,当你需要创建一个改变服务器端数据的表单时,请使用 ``method="post"** 。这不是 Django 的特定技巧;这是优秀的网站开发技巧。
|
||||||
|
* 所有针对内部 URL 的 POST 表单都应该使用 {% csrf_token %} 模板标签。
|
||||||
|
|
||||||
|
修改 `view.py`, 将Choice 逻辑灌输入其中。
|
||||||
|
|
||||||
|
```python
|
||||||
|
def vote(request, question_id):
|
||||||
|
question = get_object_or_404(Question, pk=question_id)
|
||||||
|
try:
|
||||||
|
# request.POST 是一个类字典对象 (dictionary-like object),让你可以通过关键字的名字获取提交的数据。
|
||||||
|
# request.POST['choice'] 以字符串形式返回选择的 Choice 的 ID
|
||||||
|
selected_choice = question.choice_set.get(pk=request.POST['choice'])
|
||||||
|
except (KeyError, Choice.DoesNotExist):
|
||||||
|
# 如果在 request.POST['choice'] 数据中没有提供 choice , POST 将引发一个 KeyError 。上面的代码检查 KeyError ,如果没有给出 choice 将重新显示 Question 表单和一个错误信息。
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
# 在增加 Choice 的得票数之后,代码返回一个 HttpResponseRedirect 而不是常用的 HttpResponse 、 HttpResponseRedirect 只接收一个参数:用户将要被重定向的 URL
|
||||||
|
|
||||||
|
# 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,)))
|
||||||
|
# 我们在 HttpResponseRedirect 的构造函数中使用 reverse() 函数。这个函数避免了我们在视图函数中硬编码 URL。它需要我们给出我们想要跳转的视图的名字和该视图所对应的 URL 模式中需要给该视图提供的参数。在本例中,使用在 教程第 3 部分 中设定的 URLconf, reverse() 调用将返回一个这样的字符串:'/polls/3/results/' 其中 3 是 question.id 的值。重定向的 URL 将调用 'results' 视图来显示最终的页面。
|
||||||
|
```
|
||||||
|
|
||||||
|
当有人对 Question 进行投票后, vote() 视图将请求重定向到 Question 的结果界面 (result view), edit it:
|
||||||
|
|
||||||
|
```python
|
||||||
|
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` template
|
||||||
|
|
||||||
|
```python
|
||||||
|
<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>
|
||||||
|
```
|
|
@ -1,6 +1,12 @@
|
||||||
<h1>{{ question.question_text }}</h1>
|
<h1>{{ question.question_text }}</h1>
|
||||||
<ul>
|
|
||||||
|
{% 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 %}
|
{% for choice in question.choice_set.all %}
|
||||||
<li>{{ choice.choice_text }}</li>
|
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
|
||||||
|
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
<input type="submit" value="Vote">
|
||||||
|
</form>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<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>
|
|
@ -1,8 +1,9 @@
|
||||||
from django.http import request, HttpResponse
|
from django.http import request, HttpResponse, HttpResponseRedirect
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from .models import Question
|
from .models import Question, Choice
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
latest_question_list = Question.objects.order_by('-pub_date')[:5]
|
latest_question_list = Question.objects.order_by('-pub_date')[:5]
|
||||||
|
@ -14,8 +15,31 @@ def detail(request, question_id):
|
||||||
return render(request, 'polls/detail.html', {'question': question})
|
return render(request, 'polls/detail.html', {'question': question})
|
||||||
|
|
||||||
def results(request, question_id):
|
def results(request, question_id):
|
||||||
response = "You're looking at the results of question %s."
|
question = get_object_or_404(Question, pk=question_id)
|
||||||
return HttpResponse(response % question_id)
|
return render(request, 'polls/results.html', {'question': question})
|
||||||
|
|
||||||
def vote(request, question_id):
|
def vote(request, question_id):
|
||||||
return HttpResponse("You're voting on question %s." % question_id)
|
question = get_object_or_404(Question, pk=question_id)
|
||||||
|
try:
|
||||||
|
# request.POST 是一个类字典对象 (dictionary-like object),让你可以通过关键字的名字获取提交的数据。
|
||||||
|
# request.POST['choice'] 以字符串形式返回选择的 Choice 的 ID
|
||||||
|
selected_choice = question.choice_set.get(pk=request.POST['choice'])
|
||||||
|
except (KeyError, Choice.DoesNotExist):
|
||||||
|
# 如果在 request.POST['choice'] 数据中没有提供 choice , POST 将引发一个 KeyError 。上面的代码检查 KeyError ,如果没有给出 choice 将重新显示 Question 表单和一个错误信息。
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
# 在增加 Choice 的得票数之后,代码返回一个 HttpResponseRedirect 而不是常用的 HttpResponse 、 HttpResponseRedirect 只接收一个参数:用户将要被重定向的 URL
|
||||||
|
|
||||||
|
# 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,)))
|
||||||
|
# 我们在 HttpResponseRedirect 的构造函数中使用 reverse() 函数。这个函数避免了我们在视图函数中硬编码 URL。它需要我们给出我们想要跳转的视图的名字和该视图所对应的 URL 模式中需要给该视图提供的参数。在本例中,使用在 教程第 3 部分 中设定的 URLconf, reverse() 调用将返回一个这样的字符串:'/polls/3/results/' 其中 3 是 question.id 的值。重定向的 URL 将调用 'results' 视图来显示最终的页面。
|
||||||
|
|
Loading…
Reference in New Issue