• [译]Django first steps Part4



    我们继续polls应用

    1 写一个简单的form表单

    更新我们的“polls/detail.html”,增加一个form:修改polls/templates/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>
    

    代码说明:

    • 上面的template为每个问题的选择提供了一个radio button,每个radio button的内容和choice的id联系在一起,这就是说,有人选择了问题的答案,然后提交,它将会通过post的方法提交choice=#,#表示所选中的choice的id,这就是最基本的html form表单;

    • 我们设置表单的动作是{% url 'polls:vote' question.id %},提交方法是post,这是十分重要的,因为这个动作将会把数据提交到服务器,这不是django特例,而是一个良好的web开发习惯;

    • forloop.counter表示for循环中的循环次数

    • 一旦我们创建了一个post form表单,我们需要考虑跨站请求问题,在django中只需要使用一个temaplate tag就能解决此问题,即在form表单中增加{%csrf_token %}

    现在我们来创建一个view来提交这个表单,还记得在part3里边的一条url记录吗?

    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
    

    我们也创建一个vote()的函数,增加到polls/views.py:

    def vote(request,question_id):
        question = get_object_or_404(models.Question,pk=question_id)
        try:
            selected_choice = question.choice_set.get(pk=request.POST["choice"])
        except (KeyError,models.Choice.DoesNotExist):
            return render(request,'polls/detail.html',{
                'question':question,
                'error_message':'You do not select a choice.',
            })
        else:
            selected_choice.votes += 1
            selected_choice.save()
            return HttpResponseRedirect(reverse('polls:results',args=(question.id,)))
    

    代码说明:

    • request.POST是一个类字典对象,可以通过key访问。在这个例子中,request.POST['choice'] 返回选择到的choice ID(以字符串的形式)。request.POST的值都是字符串,Djdango也提供request.GET用户获取数据。

    • request.POST['choice']如果没有取到数据,就会产生一个KeyError。并返回错误信息error_message。

    • 自增vote数量,返回HttpResponseRedirect。HttpResponseRedirect有一个单独的参数:就是想要跳转的URL (see the following point for how we construct the URL in this case).This tip isn’t specific to Django; it’s just good Web development practice.

    • 我们使用 reverse() 函数在 HttpResponseRedirect 参数中,这个函数能够避免view中的硬编码。它能够将url name转化为url字符串或正则表达式。在这个例子中,reverse() 返回字符串如下所示:

    '/polls/3/results/'
    

    修改views.py中的results函数:

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

    它和part3中的detail()很相似,只是template不一样而已;
    修改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/ 来为问题投票,每次投完票就能看见结果页面。如果你们有选择直接提交,就会看到错误信息。

    注意:
    我们的vote() view还有个小问题,先从数据库得到selected_choice对象,然后计算数,然后返回数据库。如果有两个用户同时投票,就会出现问题。这叫竞赛,如果要解决这个问题,可以使用F()来解决此问题。


    2 使用generic views: 更少代码

    像前面提到的detail() 和results() views 非常简单,还有index()view,这些 views 是通常Web 开发模式:从数据库中得到数据,通过url加载模板并渲染模板。因为这种模式太寻常了,django又给大家提供了快捷方式:“generic views” 系统;

    下面把我们的polls应用转变为generic views系统,我们需要删除一大推代码,分成下面几步:

    • 转换URLconf

    • 删除一些老的,没用的views

    • 来一些Django’s generic views

    为什么把代码搞来搞去?

    通常的,当写一个Django app, 你需要先评估generic views 是否适合解决你的问题, 从开始就使用它们要比中间再改来的好。但在我们的例子中是为了让你了解核心思想,就像在你使用计算器之前你要先学会基本运算。

    修改URLconf

    打开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> 改成了 <pk>

    修改views

    删除原来老的index, detail, and results三个views,使用新的generic views来代替:

    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):
        ...
    
    

    我们使用了两个generic views: ListView and DetailView. 分别表示 “display a list of objects” 和“display a detail page for a particular type of object.”。

    • 每个generic view需要知道它所对应的models名称

    • DetailView从url中的pk参数获取主键值,所以我们已经在url中将question_id改成了pk了。

    在默认情况下, DetailView generic view 将会使用一个叫做/_detail.html的template文件,在我们的例子中,它使用"polls/question_detail.html"。template_name 可以指定template的名称。

    相似的情况, the ListView generic view 使用默认模板文件/_list.html;我们使用 template_name 来告诉ListView我们已经存在的"polls/index.html" template。

    在上节中,我们的模板文件中有 question 和latest_question_list这种变量. 在DetailView 中 ,一旦我们使用django model,question 变量能够自动提供 Django会自动提供一个合适的环境变量名称。 然而, 对于ListView自动生成如question_list的变量名称。使用指定context_object_name变量,我们也能够自定义变量名称。我们可以在tempalte中将就django的自动产生变量,但是使用我们自己定义的变量更加容易。

    运行服务器,就能看到基于generic views的应用了,要详细了解generic views自己看文档。当你熟悉了 forms and generic views后,可以参看part 5查看如何测试django应用。

  • 相关阅读:
    Python解释器的安装 安装IDE工具 pycharm
    推荐一些基础知识,希望对大家了解python语言及计算机有一些帮助!
    Typora 技巧
    js 与或运算符 || && 妙用
    数据类型和Json格式
    从事前端开发必须要了解的CSS原理
    CSS浏览器兼容
    用jQuery Mobile创建Web App
    让你的网站变成响应式的3个简单步骤
    CSS BFC hasLayout模型
  • 原文地址:https://www.cnblogs.com/felo/p/5566337.html
Copyright © 2020-2023  润新知