本章我们将对视图和 URL 配置使用一些高超的小技巧。
【流线型化函数导入(streamlining)】
方法一:传统方法
- from django.conf.urls.defaults import *
- from mysite.views import hello, current_datetime, hours_ahead
- urlpatterns = patterns('',
- (r'^hello/$', hello),
- (r'^time/$', current_datetime),
- (r'^time/plus/(\d{1,2})/$', hours_ahead),
- )
方法二:导入 views 函数,维护较简单,针对 import 的视图模块
- from django.conf.urls.defaults import *
- **from mysite import views**
- urlpatterns = patterns('',
- (r'^hello/$', views.hello'),
- (r'^time/$', views.current_datetime ),
- (r'^time/plus/(d{1,2})/$', views.hours_ahead ),
- )
方法三:导入模块名和视图函数名,注意用引号括起来
- from django.conf.urls.defaults import *
- urlpatterns = patterns('',
- (r'^hello/$', 'mysite.views.hello' ),
- (r'^time/$', 'mysite.views.current_datetime' ),
- (r'^time/plus/(d{1,2})/$', 'mysite.views.hours_ahead' ),
- )
方法四:提取公共视图前缀,不要再前缀后面和视图字符串前面放点号,django 会自动处理
- from django.conf.urls.defaults import *
- urlpatterns = patterns('mysite.views' ,
- (r'^hello/$', 'hello' ),
- (r'^time/$', 'current_datetime' ),
- (r'^time/plus/(d{1,2})/$', 'hours_ahead' ),
- )
方法四 (2):如果我们 URLconf 没有一个公共前缀时呢?如下
- from django.conf.urls.defaults import *
- urlpatterns = patterns('',
- (r'^hello/$', 'mysite.views.hello'),
- (r'^time/$', 'mysite.views.current_datetime'),
- (r'^time/plus/(\d{1,2})/$', 'mysite.views.hours_ahead'),
- (r'^tag/(\w+)/$', 'weblog.views.tag'),
- )
解决:整个框架关注的是 urlpatterns 模块级别的变量,patterns 返回对象是可相加的。
- from django.conf.urls.defaults import *
- urlpatterns = patterns('mysite.views',
- (r'^hello/$', 'hello'),
- (r'^time/$', 'current_datetime'),
- (r'^time/plus/(\d{1,2})/$', 'hours_ahead'),
- )
- urlpatterns += patterns('weblog.views',
- (r'^tag/(\w+)/$', 'tag'),
- )
特例:django 调试模式下修改 URLconf 的行为技术,链接 debuginfo 只在 DEBUG 配置项为 True 时才有效。
- from django.conf import settings
- from django.conf.urls.defaults import *
- from mysite import views
- urlpatterns = patterns('',
- .....
- )
- if settings.DEBUG:
- urlpatterns += patterns('',
- (r'^debuginfo/$', views.debug),
- )
【url 的命名法匹配模式】
方法一:使用命名组,好比 python 函数中位置参数和关键字参数的对应关系,其语法 (?P < 组名字> 匹配模式)。
- ## 传统方法
- from django.conf.urls.defaults import *
- from mysite import views
- urlpatterns = patterns('',
- (r'^articles/(\d{4})/$', views.year_archive),
- (r'^articles/(\d{4})/(\d{2})/$', views.month_archive),
- )
- ## 使用命名组
- from django.conf.urls.defaults import *
- from mysite import views
- urlpatterns = patterns('',
- (r'^articles/(?P<year>\d{4})/$', views.year_archive),
- (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive),
- )
为了区分它们的区别,以请求 / archive/2016/12 为例,函数都进行了怎样的调用?
前者:month_archive(request,'2016','12')
后者:month_archive(request, year='2016', month='12')
缺点:虽然这样可读性强了,而且更准确了,但是冗余性也变差了;而且一个 URLconf 模式中不允许同时存在命名组和非命名组格式,优先顺序:命名组 > 非命名组 > 关键字传递额外参数。
【传递额外参数信息】
在我们写的视图函数中,我们会发现有好多视图函数类似,但又有不同,我们怎么样才能将它写的更简洁,原始模板如下:
- # urls.py
- from django.conf.urls.defaults import *
- from mysite import views
- urlpatterns = patterns('',
- (r'^foo/$', views.foo_view),
- (r'^bar/$', views.bar_view),
- )
- # views.py
- from django.shortcuts import render_to_response
- from mysite.models import MyModel
- def foo_view(request):
- m_list = MyModel.objects.filter(is_new=True)
- return render_to_response('template1.html', {'m_list': m_list})
- def bar_view(request):
- m_list = MyModel.objects.filter(is_new=True)
- return render_to_response('template2.html', {'m_list': m_list})
方法一:添加 if 判断,缺点还是把 url 耦合到代码里了,更改 url 的话还得去改视图函数。
- # views.py
- from django.shortcuts import render_to_response
- from mysite.models import MyModel
- def foobar_view(request, url):
- m_list = MyModel.objects.filter(is_new=True)
- if url == 'foo':
- template_name = 'template1.html'
- elif url == 'bar':
- template_name = 'template2.html'
- return render_to_response(template_name, {'m_list': m_list})
方法二:URLconf 中包含第三个位置参数:关键字参数
- # urls.py
- from django.conf.urls.defaults import *
- from mysite import viewsurlpatterns = patterns('',
- (r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}),
- (r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}),
- )
- # views.py
- from django.shortcuts import render_to_response
- from mysite.models import MyModel
- def foobar_view(request, template_name):
- m_list = MyModel.objects.filter(is_new=True)
- return render_to_response(template_name, {'m_list': m_list})
举例:我们要访问如下规则的 url
/mydata/jan/01/
/mydata/jan/02/
/mydata/jan/03/
# ...
/mydata/dec/30/
/mydata/dec/31/
我们可以设置 URLconf 和 视图函数如下:
urlpatterns = patterns('',
(r'^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$', views.my_view),
)
def my_view(request, month, day):
# ....
但当如果我们想增加访问一个 / mydata/birthday / 的 url,正常我们要给他一个视图函数,但我们可以用上面传递额外参数解决
urlpatterns = patterns('',
(r'^mydata/birthday/$', views.my_view, {'month':'jan','day':'06'}),
(r'^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$', views.my_view),
)
【include 其他 URLconf】
有时我们希望我们的代码用于多个 django 站点,于是我们就要考虑将我们的 URLconf 以包含的方式处理。
- from django.conf.urls.defaults import *
- urlpatterns = patterns('',
- (r'^weblog/', include('mysite.blog.urls')),
- (r'^photos/', include('mysite.photos.urls')),
- (r'^about/$', 'mysite.views.about'),
- )
注:在包含其他 urls 的 url 没有 $ 符,但包含有 /,他的意思是当 django 遇到 include,它将截断匹配的 URL,把剩余的字符串发往包含的 URLconf 进一步处理。
比如我们访问 / weblog/2007/ weblog 被此 URLconf 匹配,/ 截断的 2007 就交给了包含的 URLconf 中的 urls。
1、捕获的参数与 include
- # root urls.py
- from django.conf.urls.defaults import *
- urlpatterns = patterns('',
- (r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
- )
- # foo/urls/blog.py
- from django.conf.urls.defaults import *
- urlpatterns = patterns('',
- (r'^$', 'foo.views.blog_index'),
- (r'^archive/$', 'foo.views.blog_archive'),
- )
本例中,被捕获的 username 变量将传递给被包含的 URLconf,进而传递给那个 URLconf 中每一个视图函数。
2、额外的 URLconf 与 include
就像上边提到的,URLconf 有一个第三位置的参数,用字典表示,即下面两个配置时等效的:
- # urls.py
- from django.conf.urls.defaults import *
- urlpatterns = patterns('',
- (r'^blog/', include('inner'), {'blogid': 3}),
- )
- # inner.py
- from django.conf.urls.defaults import *
- urlpatterns = patterns('',
- (r'^archive/$', 'mysite.views.archive'),
- (r'^about/$', 'mysite.views.about'),
- (r'^rss/$', 'mysite.views.rss'),
- )
- # urls.py
- from django.conf.urls.defaults import *
- urlpatterns = patterns('',
- (r'^blog/', include('inner')),
- )
- # inner.py
- from django.conf.urls.defaults import *
- urlpatterns = patterns('',
- (r'^archive/$', 'mysite.views.archive', {'blogid': 3}),
- (r'^about/$', 'mysite.views.about', {'blogid': 3}),
- (r'^rss/$', 'mysite.views.rss', {'blogid': 3}),
- )
来源: