zoukankan      html  css  js  c++  java
  • django 官方教程翻译-part3

    在教程3的主要内容是创建视图界面

    django的设计思想:
    视图在django应用中是一个网页类型,通常它会提供特定的功能以及有一个指定的模板,比如说,在一个博客应用中,你可能需要使用以下类型的视图:
    1、博客主页——用于显示最新的文章
    2、博文显示页面——用于显示具体的博文
    3、按照年份存档的博文列表页面——用于显示指定年份的所有文章
    4、按照月份存放的博文列表页面——用于显示指定月份的所有文章
    5、按照某一天存档的博文列表页面——用于显示指定某一天的所有文章
    6、评论功能——用于处理给指定文章的发表评论

    在我们创建poll应用中,会创建以下这4个视图:
    "index"——显示最新的几个polls
    "detail"——显示具体的某个poll,还带有一个投票的表单
    "results"——显示某个特定的poll的投票结果
    投票功能——处理给在一个特定的poll的某个choice投票的功能

    在django中,web页面和其他的内容是通过试图来传递的。每个视图就表示一个简单的python 函数(或者说方法,对于基于类的视图)。根据请求的url来匹配选择一个视图(准确来讲,这里的url指的是请求url除去域名剩下的部分)

    通过url获取视图的机制就是众所周知的"URLconfs",它使用URL模式来把匹配的url映射到某个视图上。
    本教程只是使用基本的URLconfs指令,更多细节参照:https://docs.djangoproject.com/en/1.6/ref/urlresolvers/#module-django.core.urlresolvers

    1、创建第一个视图
    编辑polls/views.py,输入下面的代码:

    from django.http import HttpResponse
    
    def index(request):
        return HttpResponse("Hello, world. You're at the poll index.")

    上面的代码就是最简单的django视图了。为了让这个视图工作,需要把它映射到一个URL上,这样就需要一个URLconf
    在polls目录下创建一个URLconf,文件名叫urls.py.这时你的polls app目录应该是这样的:

    polls/
        __init__.py
        admin.py
        models.py
        tests.py
        urls.py
        views.py

    把polls/urls.py的文件内容如下:

    from django.conf.urls import patterns, url
    
    from polls import views
    
    urlpatterns = patterns('',
        url(r'^$', views.index, name='index')
    )

    下一步就是在主URLconf中添加polls/urls模块,打开mysite/urls.py,把import的内容和urlpatterns变成以下的样子:

    from django.conf.urls import patterns, include, url
    
    from django.contrib import admin
    admin.autodiscover()
    
    urlpatterns = patterns('',
        url(r'^polls/', include('polls.urls')),
        url(r'^admin/', include(admin.site.urls)),
    )

    现在你已经把index视图映射到polls这个url中了,通过访问http://localhost:8000/polls/就可以看到你在index视图定义的内容了
    这个url()函数需要传递4个参数,有两个是必须的regex(也就是正则表达式)和视图,另外两个是可选的kwargs和name.现在我们详细介绍以下这个函数的参数.
    url()参数 regex:
    "regex"是"regular expression"的缩写,正则表达式是字符串或者url(在这里)的匹配模式.django从第一个正则表达式开始遍历,知道找到和请求url匹配的正则表达式.注意,请求url的用于匹配的字符串不包括前面表示域名的部分以及后面get/post方法的参数部分.比如过,一个请求url为:http://www.example.com/myapp/,这个URLconf会匹配myapp/.在比如http://www.example.com/myapp/?page=3,URLconf也只会匹配myapp/.

    更多关于正则表达式的内容参照http://en.wikipedia.org/wiki/Regular_expression

    url() 参数view:
    当django找到与url匹配的正则表达式,就会调用该正则表达式对应的视图函数,并且把HttpRequest对象作为第一个参数

    url() 参数kwargs:
    可以向视图函数传递额外的参数,这个额外参数必须是一个字典类型的.
    url() 参数 name:往下看就知道怎么用了


    创建其他的视图:

    def detail(request, poll_id):
      return HttpResponse("You're looking at poll %s." % poll_id)
    
    def results(request, poll_id):
      return HttpResponse("You're looking at the results of poll %s." % poll_id)
    
    def vote(request, poll_id):
      return HttpResponse("You're voting on poll %s." % poll_id)

    修改polls/urls.py成以下内容:

    from django.conf.urls import patterns, url
    
    from polls import views
    
    urlpatterns = patterns('',
    # ex: /polls/
      url(r'^$', views.index, name='index'),
    # ex: /polls/5/
      url(r'^(?P<poll_id>d+)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
      url(r'^(?P<poll_id>d+)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
      url(r'^(?P<poll_id>d+)/vote/$', views.vote, name='vote'),
    )

    贴士:?P<poll_id>是把视图的关键字参数名,它的参数值为d+这个正则匹配的内容,在整个正则匹配结束后,会调用相应的视图函数,这些在匹配过程中生成的关键字参数也会传递进去.你可以看到上面定义的那三个视图都有一个叫"poll_id"的参数.

    访问"polls/34/",就会调用detail这个视图函数,显示id为34的poll,同样访问polls/34/results/和polls/34/vote分别会调用results和vote视图函数来显示在该函数中定义的内容.
    当请求/polls/34/这个url的时候,django会加载mysite.urls python模块,因为它通过ROOT_URLCONF配置项直接标识了.这个模块把当前的url根mysite.urls文件中的urlpatterns中的正则表达式,来把这个请求url路由到其他的子URLconf中进一步处理.在mysite.urls每一个正则表达式中,对应着一个include回调函数,通过这种方式应用与请求url匹配的子URLconf.
    注意:回调函数是include时,正则表达式不能使用$,因为请求url没有与正则表达式匹配的那一部分需要保留下来进行进一步的处理.

    使用这样的方式,你就可以任意的定义到polls app的url路径,比如之前只是匹配"polls/",你也可以改成"polls/content/".

    现在分析下,请求url polls/34/,这时的url映射是怎样工作的:
    首先,在mysite.urls中匹配了'^polls/'
    然后,django 把请求url中剩下为匹配的部分"34/"传递给polls.urls,为进一步匹配做准备,最后与"34/"匹配的正则表达式为r'^(?P<poll_id>d+)/$',调用相应的回调函数detail()视图,detail(request=<HttpRequest object>, poll_id='34')
    poll_id='34',来自r'^(?P<poll_id>d+),?P<poll_id>标识匹配模式名(相当一个变量名),匹配模式"d+"是用于匹配请求url正则表达式,把成功匹配到的字符串赋值给前面定义的模式,这里是poll_id.使用小括号,把匹配到的结果作为参数传递到对应的回调函数中.

    以下,使用html后缀的url不建议使用.如
    (r'^polls/latest.html$', 'polls.views.index'),

    让视图做点什么
    每个视图都自动完成这两个动作中的一个:返回一个HttpResponse对象,这个对象包含着请求页面的内容,如果请求的页面不存在就抛出一个类似Http404的异常.其他的功能就需要自己去实现了.

    修改视图index(),让它实现最新创建的5个poll,poll之间用逗号隔开.代码如下:

    from django.http import HttpResponse
    
    from polls.models import Poll
    
    def index(request):
      latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
      output = ', '.join([p.question for p in latest_poll_list])
      return HttpResponse(output)

    以上的通过硬编码的方式来实现视图,会让每次修改页面布局的时候,修改python代码,这样很麻烦.我们可以通过django的模板系统把页面布局和代码逻辑分开,让模板来负责页面布局工作.而视图就负责代码逻辑的实现.

    首先在polls目录下创建叫templates的目录.django会在这里查找用到的模板.django settings.py中的配置项TEMPLATE_LOADERS是一个包含需要用到的templates的位置列表.一个默认的模板加载器django.template.loaders.app_directories.Loader,它会在INSTALLED_APPS中注册的app目录中查找templates子目录,而不需要我们在TEMPLATE_DIRS中手动添加.

    模板的组织
    可以把所有的模板放在一个大的templates目录中,就像在教程2中的admin 的templates目录.但是,最好的方式还是每个app自己维护一个templates目录,这样的代码组织更清晰.

    在刚刚创建的polls/templates目录下创建一个叫做polls的目录,在这个目录下创建index.html文件.(polls/templates/polls/index.html.如果了解了app_directories模板加载器的工作原理,就可以知道通过polls/index.html就可以引用刚刚定义的index.html模板文件了.

    可以看到引用polls/index.html就是使用polls/templates/polls/index.html,也就是说根据polls/templates这段路径不能有效区别不同app间的模板,所以需要在app下的模板目录下创建一个polls目录来区分不同app中相同名字的模板,比如在admin app中也有index.html,那么引用名是admin/index.html.这就是把给不同的app模板,定义一个不同的命名空间.

    编辑polls/index.html,添加以下代码:

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

    现在更新一个index()视图,代码如下:

    from django.http import HttpResponse
    from django.template import RequestContext, loader
    
    from polls.models import Poll
    
    def index(request):
      latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
      template = loader.get_template('polls/index.html')
      context = RequestContext(request, {
        'latest_poll_list': latest_poll_list,
      })
      return HttpResponse(template.render(context))

    这些代码加载了polls/index.html模板,传递给他一个上下文,这个上下文是一个字典,它把python对象与模板中的模板变量名一一对应.比如这里的latest_poll_list对象对应着模板中的latest_poll_list变量.通过访问/polls/(这里略去域名部分http://127.....:8080/),即可看到我们定义的视图了.

    上面使用的是常用的传递一个请求上下文,然后返回包含渲染过后的模板的响应.django还提供了更加简单的渲染方式.
    编辑index.html,代码如下:

    from django.shortcuts import render
    
    from polls.models import Poll
    
    def index(request):
      latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
      context = {'latest_poll_list': latest_poll_list}
      return render(request, 'polls/index.html', context)

    提醒以下,一旦我们使用上面的方式渲染模板就不需要import loader和RequestContext了,但是还需要保存HttpResponse,因为detais其他三个视图还是使用传统的方式工作的.

    抛出404错误
    现在编辑details视图,代码:

    from django.http import Http404
    from django.shortcuts import render
    
    from polls.models import Poll
    # ...
    def detail(request, poll_id):
      try:
        poll = Poll.objects.get(pk=poll_id)
      except Poll.DoesNotExist:
        raise Http404
      return render(request, 'polls/detail.html', {'poll': poll})

    这里引入一个新的内容,如果访问的poll不存在就抛出一个Http404的异常.
    让detail模板工作的最快方式,编辑polls/detail.html,代码:

    {{ poll }}

    引入404异常更快捷的方式:get_object_or_404(),代码:

    from django.shortcuts import render, get_object_or_404
    
    from polls.models import Poll
    # ...
    def detail(request, poll_id):
      poll = get_object_or_404(Poll, pk=poll_id)
      return render(request, 'polls/detail.html', {'poll': poll})

    这个get_object_or_404()函数第一个参数是django模型,还有任意数量的关键字参数,这些参数前面的实现方式中传递个get()的一样.

    设计思想:
    为什么使用get_object_or_404()而不是,ObjectDoesNotExist异常或者使用model API来抛出Http404异常.这样做是为了减少model层和view层的耦合度.django的设计目标之一是松耦合.更多关于松耦合,关注django.shortcuts模块.

    还有类似功能的get_list_or_404()函数,它是在使用filter()时,如果得到的list为空就抛出Http404异常

    编辑detail.html,让它更好看一点,代码:

    <h1>{{ poll.question }}</h1>
    <ul>
      {% for choice in poll.choice_set.all %}
      <li>{{ choice.choice_text }}</li>
      {% endfor %}
    </ul>

    模板使用点操作访问对象中的变量属性.以上面代码中的{{ poll.question }}为例,首先djangp会使用字典的键值访问来查找poll对象中键名为question的值,如果不存在,就会按照对象的数据属性访问方式来查找,在这个例子中,查找成功了得到了poll对象中的question属性的值,如果再失败,就会使用列表索引的方式查找了.更多关于模板的内容,参照:https://docs.djangoproject.com/en/1.6/topics/templates/

    移除硬编码的url.
    编辑index.html,硬编码的代码如下:

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

    硬编码存在一个问题就是,一旦修改访问index视图的请求url,就需要在这些模板中逐个修改这些硬编码的url.然而,如果你在URLconf中的url函数中定义了name属性,那么你在模板里可以使用name属性值替代之前的硬编码url.因为之前在定义detail视图的url为url(r'^(?P<poll_id>d+)/$', views.detail, name='detail'),所以这里吧/polls/编程 url 'detail',具体的代码:

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

    注意:如果detail使用单引号出错,而去掉单引号就可以,那么你使用版本小于django1.5,可以通过在模板的前面加入代码,来解决:

    {% load url from future %}

    现在便利来了!如果你想要通过polls/specifics/1/来访问detail,那么你不需要修改模板,直接修改poll/urls.py,代码:

    url(r'^specifics/(?P<poll_id>d+)/$', views.detail, name='detail'),


    就可以了.

    如果有多个app,django是怎么区分那些请求url是访问哪个app的视图.比如,polls app有一个detail视图,还有另外一个app 也有detail视图.django 通过使用{% url %}标签的方式,怎样区别不同的app访问.答案就是在跟URLconf中为不同的app定义一个命名空间.

    注意:这个本人有点疑惑

    贴实现代码:

    from django.conf.urls import patterns, include, url
    
    from django.contrib import admin
    admin.autodiscover()
    
    urlpatterns = patterns('',
      url(r'^polls/', include('polls.urls', namespace="polls")),
      url(r'^admin/', include(admin.site.urls)),
    )

    相应的,需要修改index.html

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

    改成:

    <li><a href="{% url 'polls:detail' poll.id %}">{{ poll.question }}</a></li>
  • 相关阅读:
    巧用数据流让 Word 文档在线阅读
    《开源公开课分享》:Java开源框架案例分享
    存储过程
    opencv求取RGB分量
    opencv中的矩阵操作
    三维高斯模型 opencv实现
    线性均值滤波和中值滤波的比较
    opencv 画延长线
    MATLAB曲线绘制
    如何在博客园发博客时插入优酷视频
  • 原文地址:https://www.cnblogs.com/chuan-joker/p/django_tutorials_3.html
Copyright © 2011-2022 走看看