• [译]Django first steps Part3



    我们将继续part2中的polls应用,继续创建对外接口views

    1 概述

    一个views是django应用中web页面的一个“类型”,一般服务于一个特定函数和一个特定的模板,举个例子,在一个blog的应用中,可能拥有下面几个views:

    • blog主页,显示一些最新的文章入口
    • “detail”页面入口,用于每片文章的永久链接
    • 年归档页面,给定年份的每个月入口
    • 月归档页面,给定月的每日入口
    • 日归档页面,给定天的文章入口
    • 评论,处理提交评论到指定的入口

    在我们的polls应用中,我们需要下面的几个views:

    • Question “index”页面,显示最新的几个问题
    • Question “detail” 页面,显示问题内容,不显示结果但是有一个投票的form表单提交框
    • Question “results” 页面,显示特定问题的投票结果
    • vote动作,处理投票,特定的选择绑定到特定的问题上

    在django中,web页面和其他内容都是有views实现的。每个view相当与一个简单的python函数(如果是基于class的话就是类中的一个方法)。django通过遍历url来选择view。

    django提供了更优雅的url,如/newsarchive/<year>/<month>/,而不是ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B

    要从url得到view,django使用了URLconfs,一个URLconf指向了一个URL样式(使用正则表达式编写)到一个view。


    2 编写更多的view

    修改polls/views.py文件:

    from django.shortcuts import HttpResponse
    
    def index(request):
        return HttpResponse("Hello, world. You're at the polls index.")
    
    
    def detail(request,question_id):
        return HttpResponse("You're looking at question %s." % question_id)
    
    def results(request,question_id):
        response = "You're looking at the results of question %s."
        return HttpResponse(response % question_id)
    
    def vote(request,question_id):
        return HttpResponse("You're voting on question %s." % question_id)
    

    修改polls/urls.py文件:

    from django.conf.urls import url
    from . import views
    
    urlpatterns = [
        url(r'^$',views.index,name="index"),
    
        url(r'^(?P<question_id>[0-9]+)/$',views.detail,name="detail"),
        url(r'^(?P<question_id>[0-9]+)/results/$',views.results,name="results"),
        url(r'^(?P<question_id>[0-9]+)/vote/$',views.vote,name="vote"),
    ]
    

    打开浏览器,/polls/34/ 将运行detail() ,当有人请求页面的时候,说“/polls/34/ ”,django将会加载“mysite.urls ”,因为在settings里面的“ROOT_URLCONF”的设置。它会按顺序找到“urlpatterns ”参数对应的正则表达式匹配的url,首先匹配到’^polls/’, 然后到‘polls.urls’中匹配到"34/" – r’^(?P<question_id>[0-9]+)/$’, 并将url中的参数映射给 detail() view:

    detail(request=<HttpRequest object>, question_id='34')
    

    (?P<question_id>[0-9]+)中的question_id将作为参数传给view中的函数,[0-9]+表示一个或多个数字。当然,也可以直接使用html来作为url,如下:

    url(r'^polls/latest.html$', views.index), 
    

    但是,不要这么弄,这样太傻了。

    3 写view到底干了啥

    每一个view负责做下面两件事情中的一件:

    • 返回一个包含内容的HttpResponse 对象

    • 返回一个例外,如http404

    你的view能够读取数据库中的记录,能够使用django的template系统或第三方模板系统,能够生成一个pdf文件,输出xml,创建一个zip文件,通过使用python的库得到你所想要的任何东西。

    django需要的只是HttpResponse 对象,现在我们来修改一下part2中的index(),用来列举最近的5个问题。

    #_*_coding:utf-8_*_
    from django.shortcuts import HttpResponse
    from . import models
    
    def index(request):
        #倒排所有的question问题,只取前五个
        latest_question_list = models.Question.objects.order_by("-pub_date")[:5]
        #合并列表,中间用","隔开
        output = ', '.join([q.question_text for q in latest_question_list])
        return HttpResponse(output)
    

    但是有一个问题:view使用硬编码(hard-coded)方式编写,如果你想要修改页面就需要修改python代码,所以django使用template模板系统来显示页面。

    首先创建一templates的目录在polls下面,django会在这里边找模板,你的工程中TEMPLATES 设置描述了django如何加载和渲染模板, describes how Django will load and render templates. 默认设置一个 DjangoTemplates backend 中 APP_DIRS 为True. DjangoTemplates 将会在每个INSTALLED_APPS中寻找 “templates” 。

    在template下再创建一个polls的文件夹,以后可以通过polls/index.html来访问模板文件。

    Template的命名

    我们可以将所有的html文件都放置在一起,但是不方便。如果不同的app有相同的模板文件,django是不能分辨他们的,一个比较好的办法是将不同的模板放置在以app命名的文件夹中。

    修改 polls/templates/polls/index.html文件:

    ...
    {% if latest_question_list %}
    <ul>
        {% for question in latest_question_list %}
            <li><a href="/polls/{{ question.id }}">{{ question.question_text }}</a></li>
        {% endfor %}
    </ul>
    {% else %}
        <p>No polls are available.</p>
    {% endif %}
    ...
    

    修改views文件

    #_*_coding:utf-8_*_
    from django.shortcuts import HttpResponse
    from . import models
    from django.template import loader
    
    def index(request):
        #倒排所有的question问题,只取前五个
        latest_question_list = models.Question.objects.order_by("-pub_date")[:5]
        #得到一个模板
        temp = loader.get_template('polls/index.html')
        #需要传入的内容,一个字典
        context = {
            "latest_qiestion_list":latest_question_list,
        }
        #返回
        return HttpResponse(temp.render(context,request))
    ...
    
    

    A shortcut: render()

    加载和渲染模板是非常频繁的工作,如果每次使用HttpResponse来返回,比较麻黄,因此django提供了一个叫做render()的捷径:

    #_*_coding:utf-8_*_
    from django.shortcuts import HttpResponse,render
    from . import models
    
    def index(request):
        #倒排所有的question问题,只取前五个
        latest_question_list = models.Question.objects.order_by("-pub_date")[:5]
        #返回
        return render(request,"polls/index.html",{
            "latest_question_list":latest_question_list,
        })
    ...
    
    

    这样就不用导入loader了。render() 函数的第一个参数是request,第二个参数是模板,第三个参数是一个字典,用于模板传入参数使用, 返回一个给定内容和渲染模板的 HttpResponse 对象。

    4 Raising a 404 error

    下面来处理下detail视图,显示问题内容,修改polls/views.py文件:

    ...
    def detail(request,question_id):
        try:
            question = models.Question.objects.get(pk=question_id)
        except models.Question.DoesNotExist:
            raise Http404("Question does not exist")
        return render(request,"polls/detail.html",{
            "question":question
        })
    ...
    

    修改polls/templates/polls/detail.html文件,如下:

    {{ question }}
    

    A shortcut: get_object_or_404()

    我们经常get一个对象数据,如果不存在就产生一个HTTP404,django提供了一个快捷方式:

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

    Philosophy :

    为什么我们使用get_object_or_404() 或者Http404 来代替ObjectDoesNotExist 呢?

    因为我们需要联系models层和views层,django的一个重要设计理念就是维持松耦合,一些controlled 耦合 在django.shortcuts模块中介绍。

    还有一个get_list_or_404() 函数,对应的filter(),而get_object_or_404() 对应的是get()。

    5 使用模板系统(template)

    回到detail()视图,我们修改一下detail.html文件:

    <h1>
        {{ question.question_text }}
    </h1>
    <ul>
    {#question.choice_set.all:全部choice#}
    {% for choice in question.choice_set.all %}
    {#    显示choice的内容:#}
    <li>{{ choice.choice_text }}</li>
    {% endfor %}
    </ul>
    

    通过“.”来获取question表对应的列,如question.question_text获取了question的内容;同样也能使用for进行循环,注意格式。

    6 删除模板中url的硬编码

    还记得index.html中的:

    <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> 
    

    我们给他改成:

    <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
    

    其实他是通过一个{% url %} 的template tag来实现调用的,详细请参考tempalte tag。

    那么如果哪天我需要修改url的时候,如:

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

    就不需要再调整模板中的index.html文件。

    7 url的命名

    在我们的例子中只有一个app就是polls,但是在真实的django中,我们会有五个、十个甚至更多的app,怎么区分它们的url名字呢?比如说bolg和polls都有detail视图,那么使用{% url %}如何区分不同的app,方法就是在url文件中增加一行app_name = 'polls'

    from django.conf.urls import url
    from . import views
    
    app_name = "polls"  #增加此行
    urlpatterns = [
        url(r'^$',views.index,name="index"),
    
        url(r'^(?P<question_id>[0-9]+)/$',views.detail,name="detail"),
        url(r'^(?P<question_id>[0-9]+)/results/$',views.results,name="results"),
        url(r'^(?P<question_id>[0-9]+)/vote/$',views.vote,name="vote"),
    ]
    

    原来调用的时候:

    <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li> 
    

    现在这样:polls:detail

    <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> 
    

    未完待续。

  • 相关阅读:
    react项目中如何解决同时需要多个请求问题
    jq+ajax+bootstrap改写一个动态分页的表格
    Window7+vs2008+QT环境搭建
    mssql charindex
    解决NTLDR is missing,系统无法启动的方法
    基于三汇语音卡的呼叫中心开发(一)
    Wince 或Windows平台 C#调用Bitmap对象后资源应该如何释放
    Anki:插件开发
    java.lang.ClassNotFoundException: com.opensymphony.xwork2.util.ValueStack
    struts2中action之间的一种跳转
  • 原文地址:https://www.cnblogs.com/felo/p/5561779.html
Copyright © 2020-2023  润新知