Django1.5:(二)创建第一个Django应用3

      在Django 1.5 + Python 3.3的实践中,《创建第一个Django应用》前两节演示了admin应用的配置和Poll应用的数据库行为,也就是Model层,这一节主要关注Views层。

3.1 思路

      View(视图)是关于应用的特定函数,其引用相应的Template(模板)。视图层是业务逻辑层,解决显示什么的问题,而模板解决怎么显示的问题,也就是说Django使用了MVT的组合。譬如说一个Blog应用可能有这些视图:

  • Blog主页——展示最近的文章的入口;
  • 具体内容的文章——每篇文章的固定链接;
  • 按年的归档——在某个年份显示所有月份;
  • 按月的归档——显示该月的所有天
  • 按天的归档——显示改天的所有文章
  • 评论功能——处理每篇文章的评论
在这个Poll应用中,有四个视图:1)首页——展示最近的polls;2)详细内容——展示poll问题,不给出结果但又投票表格;3)结果页面——对特定poll展示投票结果;4)投票功能——处理投票操作。
       在Django中web页面和其他内容都是通过views来传递。每个view是一个简单的Python函数(或者方法,如果是基于类的视图),Django通过检查请求的URL来选择视图函数。或许我们遇到过类似“ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B”的URL,Django允许我们定制更加优美简洁的URL,一个URL模式就是选择URL的一般化形式,例如/newsarchive/<year>/<month>/,我们可以在URLconf中设定。

3.2 第一个view

       在polls/views.py中输入以下Python代码:
from django.http import HttpResponse
def index(request):
    return HttpResponse("Hello, world. You're at the poll index.")
为了调用这个视图函数,需要把它映射到URL上,所以在polls目录创建一个URLconf,命名为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中插入一个include()函数,使之成为如下的样子:
urlpatterns = patterns('',
    url(r'^polls/', include('polls.urls')),
    url(r'^admin/', include(admin.site.urls)),
)
此时在http://127.0.0.1:8000/polls/中应该能看到文本“Hello, world. You’re at the poll index.”
       url()函数有四个参数,regex和view是必须的,kwargs和name是可选的。regex也就是正则表达式,在Django中匹配url。值得注意的是,这些正则表达式不搜索GET和POST参数或者域名,例如http://www.example.com/myapp/和http://www.example.com/myapp/?page=3,URLconf都只寻找myapp/。view就是调用视图函数,也就是含有HttpRequest作为第一个位置参数的对象。kwards将任意的关键字参数放入字典传递给目标视图,在这里我们没有用到。name就是指明这个URL,以便在其他地方明确无误的使用。

3.3 更多的views

      继续写视图函数。另外三个视图函数代码如下:
def detail(request, poll_id):
    return HttpResponse("You're looking at poll %s." % pool_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模块中添加代码:
urlpatterns = patterns('',
    url(r'^$', views.index, name='index'),
    url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'),
    url(r'^(?P<poll_id>\d+)/results/$', views.results, name='results'),
    url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'),
    )
在浏览器中查看“/polls/34/”,其将调用detail方法,可以在浏览器中展示任意的ID。这是怎么样做到的呢?当请求一个页面“/polls/34/”,Django首页下载mysite.urls模块,因为它定义了根模块,然后其找到了urlpatterns的正则表达式,include()中没有$,Django把剩余的部分"34/"发送到polls.urls,由r’^(?P<poll_id>\d+)/$’匹配,进而调用detail()视图函数:detail(request=<HttpRequest object>, poll_id='34')。注意,没有必要添加.html后缀。

2.4 让views做些事

       每个视图函数可以做两种任务:1)返回一个HttpResponse对象;2)引发一个异常,例如Http404。view可以从数据库中读取记录,当然也可以不读取。我们可以用一个模板系统,例如Django自带的,或者第三方开发的。其能够产生一个PDF文件、输出XML、创建一个ZIP包等等,用python库有无尽可能。Django需要的就是HttpResponse或者一个异常。
       但是当按照以上步骤做就会发现,调用视图后也就一行文字,什么也没有做。让我们来使用Django的数据库API(《应用1》中述及)做点真正的事吧。我们在index()视图中展示最近的5个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)
这里会发现view中页面设计非常糟糕,当然这是模板需要处理的,让我们在polls目录中创建一个templates文件夹,再建一个子文件夹polls,在其中建一个index.html,也就是模板在路径polls/templates/polls/index.html。这样的放置方式是推荐的,当然你放在其他地方,Django也能找到它。模板中放入:
{% 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 %}
相应的,在view中修改为:
from django.http import HttpResponse
from django.template import Context, 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 = Context({
        'latest_poll_list': latest_poll_list,
    })
    return HttpResponse(template.render(context))
这段代码从polls/indext.html中下载模板,并且向其传递一个文本context,context是一个字典,将模板变量名映射到Python对象。
快捷方式:render()
       下载模板、填充文本、返回HttpResponse对象这是一些列常规操作,Django提供了快捷方式。可以将index()视图重新编写为:
from django.shortcuts import render
from django.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)
我们如果在所有视图中使用了这样的方法,就不需要再导入loader,Context和HttpResponse了。但detail,results和vote视图函数仍然用HttpResponse的话,还是需要导入的。render()函数第一个参数是request,第二个参数是模板,第三个可选参数是一个字典。

3.5 404错误

     接着配置poll的detail视图,其展示特定poll的问题,代码可以这样写:
from django.http import Http404

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})
这个视图在请求的ID不存在时引发了一个404异常。关于polls/detail.html我们稍后讨论,但是如果你有些迫不及待也可以先在其中只输入{{ poll }}。
快捷方式:get_object_or_404()
       使用get()并在不存在时引发404异常是非常普遍的,所以Django提供了一个快捷方式,重写detail()视图函数如下:
from django.shortcuts import render, get_object_or_404
def detail(request, poll_id):
    poll = get_object_or_404(Poll, pk=poll_id)
    return render(request, 'polls/detail.html', {'poll': poll})
此函数以Django model作为第一个参数和一个任意的关键字参数,在对象不存在时引发404异常。这样做的好处是减小模型层和视图层的耦合度,在django.shortcuts模块中有更多控制耦合的内容。
       还存在一个get_list_or_404(),其用filter()方式代替get(),如果list为空则返回一个404异常。

3.6 写一个404视图

       http404也就是常说的没有找到页面,在Django中其也是一个普通视图,其内置的hander404在django.views.defaults.page_not_found(),但是我们往往不堪忍受默认界面,我们可以自己定制一个。
       有两点注意事项:1)在settings模块如果DEBUG设置为True,404视图将不会被调用,直接显示错误信息;2)如果不存在相应的URL路径也会调用404视图函数。

3.7 写一个50视图

      也就是服务器错误,同样的根URLconf会定义一个hander500,指定调用的视图,我们同样可以在模板根目录下创建一个500.html模板。

3.8 使用模板系统

      回到detail()视图,我们编写这样的模板代码:
<h1>{{ poll.question }}</h1>
<ul>
{% for choice in poll.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
      模板系统采用点查找的方式获得变量属性。例如{{ poll.question }},首先Django进行字典查找对象poll,失败后尝试属性查找,这里成功了,如果再失败就进行列表索引查找。在{% for %}中对poll.choice_set.all循环,因为其实可迭代对象。

3.9 去除模板中植入式的URLs

       当我们在index.html中写一个连接,其像这样部分植入<li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>,这种方式的耦合度强,不利于在项目中修改URLs。既然我们已经在polls.urls模块中定义了url()的name参数,我们就可以去除那样的植入式URL,使用{% url %}的模板标签来修改:
<li><a href="{% url ’detail’ poll.id %}">{{ poll.question }}</a></li>,注意在1.5版本之前不需要在detail上添加引号。
这样,如果我们需要修改url的显示,我们在polls.urls.py中修改如url(r’^specifics/(?P<poll_id>\d+)/$’, views.detail, name=’detail’)即可。这样,URL是URL,模板是模板!

3.10 URL names命名空间

       这里我们只有一个应用polls,实际中可能有10个,20个或者更多的应用。Django是如何区分这些URL的名称的呢?比如说有一打detail()。答案是在根URLconf中添加命名空间。在项目mysite/urls.py中添加:
urlpatterns = patterns('',
    url(r'^polls/', include('polls.urls', namespace='polls')),
    url(r'^admin/', include(admin.site.urls)),
)
       在模板中我们在detail视图中指明命名空间:
<li><a href="{% url 'polls:detail' poll.id %}">{{ poll.question }}</a></li>
       关于polls的视图和模板在本节暂时告一段落,下一节我们将继续补充和完善它们,并介绍form过程和通用视图。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值