Django教程:第一个Django应用程序(3)

时间:2023-11-26 12:15:56

Django教程:第一个Django应用程序(3)

2013-10-08 磁针石

#承接软件自动化实施与培训等gtalk:ouyangchongwu#gmail.comqq 37391319

#博客:http://blog.csdn.net/oychw

#版权所有,转载刊登请来函联系

# 深圳测试自动化python项目接单群113938272深圳广州软件测试开发 6089740

#深圳湖南人业务户外群 66250781武冈洞口城步新宁乡情群49494279

#参考资料:https://docs.djangoproject.com/en/1.5/intro/tutorial01/

# http://django-chinese-docs.readthedocs.org/en/latest/intro/tutorial01.html

#本文的图片没有上传,完整的文档参见:python模块笔记:http://t.cn/z8ggk71

本节关注创建公共界面 –视图(views)。

哲学

在 Django 应用中,视图是一“类”具有特定功能和模板的网页。 例如,在博客应用中,你可能会有以下视图:

§  博客首页 – 显示最新发表的博客。

§  博客详细页面 – 单个博客的固定连接。

§  基于年份的归档页 – 显示指定年份所有月份的博客。

§  基于月份的归档页 – 显示指定月份所有日期的博客。

§  基于日期的归档页 –显示指定日期所有博客。

§  评论 – 为指定博客处理评论。

在我们的投票应用中,将有以下四个视图:

§  Poll“index” 页 – 显示最新投票。

§  Poll“detail” 页 – 显示投票,无投票结果,但是可以投票。

§  Poll“results” 页 – 显示指定的投票结果。

§  投票 – 处理投票。

在 Django 中,网页及其他内容是由视图展现。视图就是简单的 Python 函数(或方法)。Django 会通过检查URL(确切地说是域名之后的那部分 URL)来匹配一个视图。

URL 模式是URL的通用形式- 比如: /newsarchive/<year>/<month>/.

Django 通过‘URLconfs’把URL 模式 (正则表达式)映射到视图。本教程中介绍URLconfs 的基本指令,更多信息参见django.core.urlresolvers

第一个视图

编辑polls/views.py:

from django.http importHttpResponse

defindex(request):

returnHttpResponse("Hello, world. You're at the poll index.")

然后配置URLconf 。在 polls 目录下创建一个名为 urls.py 的 URLconf 文档。

from django.conf.urls importpatterns,url

from polls importviews

urlpatterns=patterns('',

url(r'^$',views.index,name='index')

)

配置 mysite/urls.py 调用polls.urls:

fromdjango.conf.urls import patterns, include, url

fromdjango.contrib import admin

admin.autodiscover()

urlpatterns= patterns('',

url(r'^polls/', include('polls.urls')),

url(r'^admin/', include(admin.site.urls)),

)

启动开发服务器:python manage.py runserver 192.168.4.13:8000。访问:http://192.168.4.13:8000/polls/,将可以看到:Hello, world.You're at the poll index。

现在你在 URLconf 中配置了 index 视图。通过浏览器访问 http://localhost:8000/polls/ ,如同你在 index 视图中定义的一样,你将看到“Hello, world. You’re at the poll index.” 文字。

url() 两个必选参数: regex 和view, 两个可选参数:kwargs和name。

regex是regularexpression 的简写,这是字符串模式匹配的语法,在 Django 中就是url 模式。 Django 将请求的URL 从上至下依次匹配列表中的正则表达式,直到匹配为止。

注意这些正则表达式不会匹配 GET 和 POST 参数以及域名。 例如:针对请求http://www.example.com/myapp/,URLconf 将只查找 myapp/。而在http://www.example.com/myapp/?page=3 也是如此。

当 Django 匹配了正则表达式就会调用响应的view函数, HttpRequest作为第一个参数和正则表达式 “捕获” 值的作为其他参数。 如果是简单正则捕获,将按顺序位置传参数;如果是命名正则捕获,将按关键字传参数值。

kwargs任意关键字参数,可传一个字典至目标视图。

Name:给你的URL取名,让你在 其他地方尤其是模板中可以更方便地引用它,特别是在模板中。 这一强大的功能可允许你通过一个文件就可修改项目中的全局URL 模式。

更多视图

现在我们再增加一些有参数的视图:

defdetail(request, poll_id):

return HttpResponse("You're looking atpoll %s." % poll_id)

defresults(request, poll_id):

return HttpResponse("You're looking atthe results of poll %s." % poll_id)

defvote(request, poll_id):

return HttpResponse("You're voting onpoll %s." % poll_id)

添加对应的url映射:

fromdjango.conf.urls import patterns, url

frompolls 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'),

)

在你的浏览器中访问 http://192.168.4.13:8000/polls/34/ 。将运行detail()方法并显示URL 中提供的ID 。/polls/34/results和/polls/34/vote/也有类似显示。

访问网站页面时,比如/polls/34/时,Django 会加载mysite.urls模块(settings中的ROOT_URLCONF = 'mysite.urls'),然后找到urlpatterns变量并依次匹配正则表达式。include()表示导入其他 URL配置。include()中的正则表达式没有$(字符串结尾的匹配符),尾部是一个反斜杠。当 Django 解析include()时,它截取匹配部分而把剩余的字符串交由子URLconf 作进一步处理。这样include()使 URLs 即插即用。

当用户访问 “/polls/34/”:

§  Django 匹配'^polls/'

§  Django 截取匹配文本polls/,发送34/ 到‘polls.urls’ URLconf ,后者匹配r'^(?P<poll_id>\d+)/$' 导致如下调用

detail(request=<HttpRequestobject>, poll_id='34')

添加些实际的功能

每个视图返回一个包含请求页面的内容HttpResponse对象或者抛出一个异常,例如 Http404

视图可以选择是否读取数据库记录,是否使用Django或python第三方模板系统。视图可以生成PDF 文件,输出 XML ,创建 ZIP 文件等。可以使用任何 Python 库。

下面index视图显示系统中最新发布的 5 个调查问卷,以逗号分割并按发布日期排序::

fromdjango.http import HttpResponse

from polls.modelsimport Poll

def index(request):

latest_poll_list = Poll.objects.order_by('-pub_date')[:5]

output = ','.join([p.question for p in latest_poll_list])

returnHttpResponse(output)

通过模板可以分离python和设计。

在polls目录下创建templates目录。Django 将会在那寻找模板。

Django 的TEMPLATE_LOADERS配置中查找模板的方法。 django.template.loaders.app_directories.Loader 就会在INSTALLED_APPS的templates子目录下查找模板。

在你刚创建的templates目录下,创建polls(防止不同应用有重名的模板)的目录,并在其中创建文件index.html。你的模板位于polls/templates/polls/index.html 。简写为polls/index.html就可。

{% iflatest_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 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/index.html 模板并传递 context。context是一个映射模板变量为Python 对象的字典。

在你的浏览器中加载 “/polls/” 页,你应该看到一个列表,包含了在教程 第1部分 中创建的 “What’sup” 调查。而链接指向 poll 的具体页面。

上述加载模板过程很常用,为此Django提供了快捷方式:render(),用于加载模板,填充上下文并返回一个含有模板渲染结果的HttpResponse对象。

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)

render() 函数中第一个参数是 request 对象,第二个参数是一个模板名称,第三个是一个字典类型的可选参数。它将返回根据给定模板和上下文渲染的HttpResponse对象。

抛出 404 异常

显示具体投票的视图detail:

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})

poll 的 ID 不存在,视图将抛出Http404异常。我们稍后讨论如何设置polls/detail.html模板,若是你想快速运行上面的例子,在模板文件中添加如下代码:

{{ poll }}

同样这也有个快捷方式。

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})

get_object_or_404()使用Django 模型作为第一个参数,还有一些任意数量的传递到模型管理器的get()的关键字参数,若对象不存在时就抛出Http404异常。

为什么不在更高层自动捕获 ObjectDoesNotExist异常, 或者由模型 API 抛出 Http404异常?

因为那样会使模型层与视图层耦合在一起。保持松耦合Django 最重要的设计目标之一。一些耦合控制在 django.shortcuts 模块中介绍。

get_list_or_404()get_object_or_404()类似– 不过执行的是 filter() 而不是 get() 。若返回的是空列表将抛出 Http404 异常。

编写404 ( 页面未找到 ) 视图

Django 载入特定的视图来处理 404 错误,根据你的 root URLconf (仅root URLconf)中设置的handler404变量来查找视图。

一般不需要编写 404 视图。若没有设置handler404,默认使用内置的django.views.defaults.page_not_found()视图。或者在你的模板目录根目录

编写一个 500 ( 服务器错误 ) 视图

类似的,你可以在 root URLconf 中定义 handler500 变量,在服务器发生错误时调用对应的视图。视图代码产生的运行时错误会发生服务器错误。

同样,在模板根目录下创建一个500.html模板并且添加些像“出错了”之类的内容。

使用模板系统

修改polls/detail.html :

<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即Python 代码poll.choice_set.all(),它将返回一组可迭代的Choice对象。

更多模板的信息参见 templateguide 。

移除模板中硬编码的 URLS

polls/index.html中,polls/{{ poll.id }}等是硬编码:

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

可以在 url 配置中使用 {% url %} 模板标记来移除特定的 URL 路径依赖:

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

其原理就是在 polls.urls 模块中寻找指定的URL 定义。 你知道命名为 ‘detail’ 的 URL 就如下所示那样定义的一样::

...
# 'name' 的值由 {% url %} 模板标记来引用
url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'),
...

如果你想将 polls 的 detail 视图的 URL 改成polls/specifics/12,那不需要在模板(或者模板集)中修改而只要在 polls/urls.py 修改:

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

URL命名空间:

如果多个应用都有名字为 detail的 视图,需要在 root URLconf 配置中添加命名空间。修改mysite/urls.py文件:

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)),
)

修改polls/index.htm从:

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

为包含命名空间的 detail 视图:

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