博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
民意调查Django实现(四)
阅读量:5764 次
发布时间:2019-06-18

本文共 5727 字,大约阅读时间需要 19 分钟。

版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/50329533

我们接着上一小节的末尾开始学习,在上一个小节中,我们主要是了解了Django中的模板,即templates的使用。在这个小节中,我们主要关注于简单的表单处理并且裁剪我们的代码。

编写一个简单的表单

我们来更新一下我们的detail模板(“polls/detail.html”),添加HTML的<form>元素。

{
{ question.question_text }}

{% if error_message %}

{

{ error_message }}

{% endif %}
{% csrf_token %}{% for choice in question.choice_set.all %}
{% endfor %}

简单描述一下:

- 上面的模板为每一个question展示了一组单选按钮。每一个按钮的值(value)是相关问题的选项ID。每一个按钮的名称是”choice”。也就是意味着,当用户选择其中一个选项框并且提交表单的时候,将会发送post数据choice=#,其中#就是对应的选择的选项的ID。这个是HTML表单的基本概念。
- 我们设置表单的action为{% url 'polls:vote' question.id %},并且我们设置method="post"。使用post方式(和使用get方式对应)是非常重要的,因为提交表单的行为将会改变服务端的数据。无论你什么时候创建能够修改服务端数据的表单的时候,一定要使用methon="post"。这个技巧不是Django专有的。这个仅仅就是好的网页开发技巧。
- forloop.counter标示for标签在这个循环中出现的次数。
- 既然我们创建了一个POST表单(该表单可能会影响修改数据),我们就需要去担心通过站点请求的伪装。幸运的是,我们不必太过担心,因为Django提供了一个简单易用的系统来阻止他。简单来说,目标是内部URLs的所有的POST表单都应该使用{% crsf_token %}模板标签。

现在,我们来创建处理提交数据的视图。在上一个小节中,我们创建了包含下面这一行的URLconf。

polls/urls.py

url(r'^(?P
\d+)/vote/$',views.vote,name='vote'),

我们也创造了一个vote()函数的临时实现。现在我们来真正使用起来。向polls/views.py中添加下面的代码:

# -*- coding:utf-8 -*-from django.http import HttpResponse,HttpResponseRedirectfrom django.shortcuts import get_object_or_404,renderfrom django.core.urlresolvers import reversefrom polls.models import Question....def vote(request,question_id):    p = get_object_or_404(Question,pk=question_id)    try:        selected_choice = p.choice_set.get(pk=request.POST['choice'])    except (KeyError, Choice.DoesNotExit):        return render(request,'polls/detail.html',{            'question':p,            'errot_message':"You did not select a choice."        })    else:        selected_choice.votes += 1        selected_choice.save()        # 每次成功处理POST数据之后一定要返回HttpResponseRedirect。        # 这个可以避免二次提交        return HttpResponseRedirect(reverse('polls/results',args=(p.id)))

该代码包含下面几个事情:

  • request.POST是一个类似于字典的对象,能够使我们通过键名称去访问提交的数据。在这个例子中,request.POST['choice']返回的是选中的选项的ID,这里是字符串。request.POST值一直是字符串。

    注意,Django也提供了request.GET去访问GET数据的方式,但是对于request.POST来说只有在代码中才能获取到相应的数据,这个大家可以去了解get方式请求和post方式请求的区别。

  • 如果在POST数据中没有提供choice选项,那么request.POST['choice']将会抛出KeyError异常。上面的代码检查KeyError异常,如果没有提供choice的话,重新显示带有错误信息的question表单。

  • 在增加了选项数量之后,代码返回一个HttpResponseRedirect而不是一个正常的HttpResponse。HttpResponseRedirect使用一个单一的参数:也就是用户将要重定向的url地址。
  • 在这个例子的HttpResponseRedirect结构中我们使用reverse()函数。这个函数帮助我们避免发生视图函数中硬编码一个URL地址。他被给予我们想要传递到的视图名称和指向视图的URL正则中的变量部分。在这个例子中,使用我们在上一小节中设置的URLconf,最终reverse()调用将会返回类似于下面的字符串:'/polls/3/results',其中的3是p.id的值。这个重定向URL然后调用’results’视图去展示最终的页面。

在用户对相应问题投票之后,vote()视图将会重定向到这个问题的results页面。现在我们来重写这个页面:

def results(request, question_id):    question = get_object_or_404(Question, pk=question_id)    return render(request, 'polls/results.html', {
'question': question})

下面我们来添加results模板:

创建一个polls/results.html模板:

polls/templates/polls/results.html

{
{ question.question_text }}

    {% for choice in question.choice_set.all %}
  • {
    { choice.choice_text }} -- {
    { choice.votes }} vote{
    { choice.votes|pluralize }}
  • {% endfor %}
Vote again?

现在,我们在浏览器中进入/polls/1/中去为相应的问题去投票。每次投票后你都能看到相应的结果更新。如果你没有选择选项而点击提交的话,你将会看到错误信息。

下面来看一下我的运行结果:

这里写图片描述

这里写图片描述


使用通用视图:减少代码更好

detail()和results()视图是非常简单的 - 就像是上面提到的,太冗余了。展示投票列表的index()视图也是一样的。

这些视图代表着基本Web开发的通用例子:通过URL传来的参数从数据库获取数据,加载模板并且返回一个渲染模板。因为这些都是雷同的,所以Django提供了一个快捷方式,成为”通用视图”系统。

通用试图系统抽象除了通用正则,这使得我们可能不需要编写Python代码也能构件一个应用。

下面让我们的应用使用通用视图,所以我们可以删除一大些代码了。我们仅仅需要几步就能做出转换。

  1. 转换URLconf
  2. 删除一些旧的,不需要的视图
  3. 基于Django的通用视图引入新的视图

修改URLconf

首先,打开polls/urls.py并且像下面这样修改:

from django.conf.urls import patterns,urlfrom polls import viewsurlpatterns = patterns('',    # ex: /polls/    url(r'^$', views.IndexView.as_view(),name='index'),    # ex: /polls/5/    url(r'^(?P
\d+)/$',views.DetailView.as_view(),name='detail'), # ex: /polls/5/results url(r'^(?P
\d+)/results/$',views.ResultsView.as_view(),name='results'), # ex: /polls/5/vote/ url(r'^(?P
\d+)/vote/$',views.vote,name='vote'),)

注意,正则匹配中间的<question_id>改成了<pk>


修改视图

下一步,我们将要移除我们旧的index,detail和results视图,然后使用Django的通用视图。打开polls/view.py文件,并且像下面这样修改:

# -*- coding:utf-8 -*-from django.http import HttpResponse,HttpResponseRedirectfrom django.shortcuts import get_object_or_404,renderfrom django.core.urlresolvers import reversefrom django.views import genericfrom polls.models import Questionclass 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”的主键,这就是为什么刚刚在urls.py中修改question_idpk的原因了。

默认情况下,DetailView通用视图使用称为<app name>/<model name>_detail.html作为模板。在我们的例子中,他会使用模板”polls/question_detail.html”。属性template_name被用来告诉Django使用能够哪一个模板代替默认模板。我们也为results指定了template_name。

相似的,ListView通用视图使用默认的模板,称为<app name>/<model name>_list.html,我们同样为他指定了我们自己的模板。

在之前的小节中,模板已经被提供了context,也就是上下文,该上下文包含question和latest_question_list变量。对于DetailView,question已经被自动提供了。我们使用Django的模型(Question),所以Django能够决定为上下文变量使用一个近似的名称。然而,对于ListView,自动生成的上下文变量是question_list。为了重写,我们可以使用context_object_name属性,指定我们想要使用的latest_question_list。这样的话,通过Django通用视图提供的属性,我们就可以指定我们想使用的变量了。

下面我们来运行一下,看一下效果:

运行效果和上面的。

你可能感兴趣的文章
多重影分身:一套代码如何生成多个小程序?
查看>>
Oracle将NetBeans交给了Apache基金会
查看>>
填坑记:Uncaught RangeError: Maximum call stack size exceeded
查看>>
SpringCloud之消息总线(Spring Cloud Bus)(八)
查看>>
DLA实现跨地域、跨实例的多AnalyticDB读写访问
查看>>
实时编辑
查看>>
KVO原理分析及使用进阶
查看>>
【348天】每日项目总结系列086(2018.01.19)
查看>>
【JS基础】初谈JS现有的数据类型
查看>>
【294天】我爱刷题系列053(2017.11.26)
查看>>
Microsoft发布了Azure Bot Service和LUIS的GA版
查看>>
Google发布Puppeteer 1.0
查看>>
.NET开源现状
查看>>
可替换元素和非可替换元素
查看>>
2016/08/25 The Secret Assumption of Agile
查看>>
(Portal 开发读书笔记)Portlet间交互-PortletSession
查看>>
搭建vsftpd服务器,使用匿名账户登入
查看>>
AMD改善Linux驱动,支持动态电源管理
查看>>
JAVA中循环删除list中元素的方法总结
查看>>
Java虚拟机管理的内存运行时数据区域解释
查看>>