代码地址:
https://github.com/Danielyan86/Django-Polls.gitgithub.com参考教程:
Writing your first Django app, part 3
Writing your first Django app, part 4
创建更多的视图
Django的视图层是用来处理前端页面的请求的方法,在Django里面可以通过简单的匹配规则找到后端的方法。
在这个poll应用中,我们定义四个主要views:
- 问题索引页面(index)-显示最新的问题
- 详细页面(details)- 显示问题内容
- 结果页面(results)- 显示一个特定问题的结果
- 投票页面(vote)- 处理一个问题的投票
views通过url的匹配模式找到对应的方法,以index页面为例:
顶层mysite.urls定义了第一级URL的访问路径的匹配模式:
urlpatterns = [
path('admin/', admin.site.urls),
path('polls/', include('polls.urls')),
path('', include('polls.urls')),
path('index/', include('polls.urls')),
]通过include 加载下级的URL匹配模式到urls里面,比如polls.url里面定义的url pattern
Django也支持更复杂的url模式匹配,比如加了<int:question_id>标签
urlpatterns = [
path('', views.index, name='index'),
# ex: /polls/5/ 通过view.detail 找到对应的在view里面定义的detail方法
path('<int:question_id>/', views.detail, name='detail'),
# ex: /polls/5/results/
path('<int:question_id>/results/', views.results, name='results'),
# ex: /polls/5/vote/
path('<int:question_id>/vote/', views.vote, name='vote'),
]当我们访问http://127.0.0.1:8000/index/ 时候index方法会接收到前端的一个http请求,这个请求封装在request里面,然后通过path('', views.index, name='index')找到了polls里面定义的index方法,index方法处理请求之后返回相应的内容到前端:
# use template
def index(request):
# return HttpResponse("Hello, world. You're at the polls index.")
latest_question_list = Question.objects.order_by('-pub_date')[:5] # 取出对象按时间排序,然后取前五个
context = {'latest_question_list': latest_question_list} #定义模板渲染的字典
return render(request, 'polls/index.html', context) #渲染模板,返回http response给前端这里面没有直接返回内容,而是通过django的模板引擎渲染了一个我们在templates下面自定的一个模板
模板渲染路径:
可以在settings里面的TEMPLATES配置,默认会从templates里面找
模板内容
{#如果latest_question_list变量存在,则加载下面的代码#}
{% if latest_question_list %}
<ul>
{#遍历latest_question_list里面的值#}
{% for question in latest_question_list %}
{#取出对应的值#}
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}访问127.0.0.1:8000/index 得到以下内容:
命名空间
模板里面使用URL标签来寻找对应的url
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>如果有更多的应用,比如poll2,polls3,怎么来区分呢?答案是通过命名空间
在urls里面添加app_name
from . import views
app_name = 'polls'
urlpatterns = [更新模板:
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>问题显示部分完成了,接下我们需要完成投票功能,这个时候需要创建提交表单页面。
提交表单
通过在前端创建表单提交功能,向后端发起一个post的数据提交请求,也就是我们的投票工程
创建模板:
<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表还没有数据,通过脚本write_data_into_DB.py 添加数据到数据库,这时可以再投票页面开始投票了
对应投票的视图代码:
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 # 投票结果写入DB
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是一个字典,里面存储了前端post过来的数据,通过key找到全段提交的内容
- request.POST['choice']会报出keyError异常,添加try-except代码处理异常
- 完成投票之后使用HttpResponseRedirect跳转到结果页面
投票之后可以看到结果:
到这时,一个简单的投票器应用完成了。