在Django中创建URLconf相关的通用视图的方法
抽取出我们代码中共性的东西是一个很好的编程习惯。比如,像以下的两个Python函数:
defsay_hello(person_name): print'Hello,%s'%person_name defsay_goodbye(person_name): print'Goodbye,%s'%person_name
我们可以把问候语提取出来变成一个参数:
defgreet(person_name,greeting): print'%s,%s'%(greeting,person_name)
通过使用额外的URLconf参数,你可以把同样的思想应用到Django的视图中。
了解这个以后,你可以开始创作高抽象的视图。更具体地说,比如这个视图显示一系列的Event对象,那个视图显示一系列的BlogEntry对象,并意识到它们都是一个用来显示一系列对象的视图的特例,而对象的类型其实就是一个变量。
以这段代码作为例子:
#urls.py fromdjango.conf.urls.defaultsimport* frommysiteimportviews urlpatterns=patterns('', (r'^events/$',views.event_list), (r'^blog/entries/$',views.entry_list), ) #views.py fromdjango.shortcutsimportrender_to_response frommysite.modelsimportEvent,BlogEntry defevent_list(request): obj_list=Event.objects.all() returnrender_to_response('mysite/event_list.html',{'event_list':obj_list}) defentry_list(request): obj_list=BlogEntry.objects.all() returnrender_to_response('mysite/blogentry_list.html',{'entry_list':obj_list})
这两个视图做的事情实质上是一样的:显示一系列的对象。让我们把它们显示的对象的类型抽象出来:
#urls.py fromdjango.conf.urls.defaultsimport* frommysiteimportmodels,views urlpatterns=patterns('', (r'^events/$',views.object_list,{'model':models.Event}), (r'^blog/entries/$',views.object_list,{'model':models.BlogEntry}), ) #views.py fromdjango.shortcutsimportrender_to_response defobject_list(request,model): obj_list=model.objects.all() template_name='mysite/%s_list.html'%model.__name__.lower() returnrender_to_response(template_name,{'object_list':obj_list})
就这样小小的改动,我们突然发现我们有了一个可复用的,模型无关的视图!从现在开始,当我们需要一个视图来显示一系列的对象时,我们可以简简单单的重用这一个object_list视图,而无须另外写视图代码了。以下是我们做过的事情:
我们通过model参数直接传递了模型类。额外URLconf参数的字典是可以传递任何类型的对象,而不仅仅只是字符串。
这一行:model.objects.all()是鸭子界定(原文:
我们使用model.__name__.lower()来决定模板的名字。每个Python的类都有一个__name__属性返回类名。这特性在当我们直到运行时刻才知道对象类型的这种情况下很有用。比如,BlogEntry类的__name__就是字符串'BlogEntry'。
这个例子与前面的例子稍有不同,我们传递了一个通用的变量名给模板。当然我们可以轻易的把这个变量名改成blogentry_list或者event_list,不过我们打算把这当作练习留给读者。
因为数据库驱动的网站都有一些通用的模式,Django提供了一个通用视图的集合,使用它可以节省你的时间。我们将会在下一章讲讲Django的内置通用视图。
提供视图配置选项
如果你发布一个Django的应用,你的用户可能会希望配置上能有些自由度。这种情况下,为你认为用户可能希望改变的配置选项添加一些钩子到你的视图中会是一个很好的主意。你可以用额外URLconf参数实现。
一个应用中比较常见的可供配置代码是模板名字:
defmy_view(request,template_name): var=do_something() returnrender_to_response(template_name,{'var':var})
了解捕捉值和额外参数之间的优先级额外的选项
当冲突出现的时候,额外URLconf参数优先于捕捉值。也就是说,如果URLconf捕捉到的一个命名组变量和一个额外URLconf参数包含的变量同名时,额外URLconf参数的值会被使用。
例如,下面这个URLconf:
fromdjango.conf.urls.defaultsimport* frommysiteimportviews urlpatterns=patterns('', (r'^mydata/(?P<id>\d+)/$',views.my_view,{'id':3}), )
这里,正则表达式和额外字典都包含了一个id。硬编码的(额外字典的)id将优先使用。就是说任何请求(比如,/mydata/2/或者/mydata/432432/)都会作id设置为3对待,不管URL里面能捕捉到什么样的值。
聪明的读者会发现在这种情况下,在正则表达式里面写上捕捉是浪费时间的,因为id的值总是会被字典中的值覆盖。没错,我们说这个的目的只是为了让你不要犯这样的错误。