DjangoBook笔记-5

# date: Apr.27,2010
# by fatway#gmail.com

27. Urlconf配置技巧
    前面的学习中,在urls.py中进行页面视图配置时,使用的是模块函数导入方法
        from mysite.views import hello, current_datetime, hours_ahead
        
    可以将该方法提升到模块级别进行
        from django.conf.urls.defaults import *
        from mysite import views  # 直接导入views模块
        urlpatterns = patterns('',
            (r'^hello/$', views.hello),  # 引用views中的函数
            (r'^time/$', views.current_datetime),
            (r'^time/plus/(d{1,2})/$', views.hours_ahead),
        )
    
    Django还提供一种通过导出函数位置字符串的方式还识别视图
        from django.conf.urls.defaults import *
        urlpatterns = patterns('',
            (r'^hello/$', 'mysite.views.hello'),  # 注意是<字符串>形式
            (r'^time/$', 'mysite.views.current_datetime'),
        )
        
    上面的新方法,还可以将公共部分提取出来
        from django.conf.urls.defaults import *
        urlpatterns = patterns('mysite.views',  # 公共部分
            (r'^hello/$', 'hello'),  # 注意是<字符串>形式
            (r'^time/$', 'current_datetime'),
        )
        
    当引用多视图时,多个公共前缀可以分别引入
        from django.conf.urls.defaults import *
        urlpatterns = patterns('mysite.views',  # 公共部分
            (r'^hello/$', 'hello'),  # 注意是<字符串>形式
            (r'^time/$', 'current_datetime'),
        )
        urlpatterns += patterns('weblog.views',  # 增加patterns对象
            (r'^tag/(\w+)/$', 'tag'),
        )
        
    调试模式特例
        from django.conf import settings
        from django.conf.urls.defaults import *
        from mysite import views
        
        urlpatterns = patterns('',
            (r'^$', views.homepage),
            (r'^(\d{4})/([a-z]{3})/$', views.archive_month),
        )
        
        if settings.DEBUG:  # 当settings中debug设置为真时执行
            urlpatterns += patterns('',
                (r'^debuginfo/$', views.debug),
            )
        

28. Url中使用命名组
    无命名组的URLconf
        urlpatterns = patterns('',
            (r'^articles/(\d{4})/$', views.year_archive),
            (r'^articles/(\d{4})/(\d{2})/$', views.month_archive),
        )
        调用时,请求请求 /articles/2006/03/ 
        相当于month_archive(request, '2006', '03')
        
    有命名组的URLconf
        urlpatterns = patterns('',
            (r'^articles/(?P<year>\d{4})/$', views.year_archive),
            (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive),
        )
        调用时,请求请求 /articles/2006/03/ 
        相当于month_archive(request, year='2006', month='03')
        好处是可以自定义顺序


# date: Apr.29,2010

29. 向视图函数中传递额外参数
    当两个视图十分类似时(除了模板不同,其它大致一样),可以合并为一个
    首先在urls.py中可以配置相当的视图
        urlpatterns = patterns('',
            (r'^(foo)/$', views.foobar_view),
            (r'^(bar)/$', views.foobar_view),
        )

    然后在视图views.py中进行判别
        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})

    针对上面的例子,Django提供了一种优雅的解决方案
    在URLconf中还可以向其传递第三个参数:指定模板的字典
        # urls.py
        
        from django.conf.urls.defaults import *
        from mysite import views
        
        urlpatterns = 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})


30. 伪造捕捉到的URLconf值
    当应用要捕捉如下特定日期的url时
        /mydata/jan/01/
        /mydata/feb/14/
        # ...
    可以使用conf
        (r'^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$', views.my_view),
    函数原型为
        def my_view(request, month, day):
            # ....        

    但如果想要增加一个url, /mydata/birthday/ 其等价于 /mydata/jun/06
    显然上面的urlconf无法捕捉到该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),
        )


31. 创建通用视图
    通过对类型进行抽象,可以简化一些操作
    以这段代码作为例子:
        # urls.py
        from django.conf.urls.defaults import *
        from mysite import views
        
        urlpatterns = patterns('',
            (r'^events/$', views.event_list),
            (r'^blog/entries/$', views.entry_list),
        )
        
        # views.py
        from django.shortcuts import render_to_response
        from mysite.models import Event, BlogEntry
        
        def event_list(request):
            obj_list = Event.objects.all()
            return render_to_response('mysite/event_list.html', {'event_list': obj_list})
        
        def entry_list(request):
            obj_list = BlogEntry.objects.all()
            return render_to_response('mysite/blogentry_list.html', {'entry_list': obj_list})
    这两个视图做的事情实质上是一样的: 显示一系列的对象。 
    把它们显示的对象的类型抽象出来:
        # urls.py
        from django.conf.urls.defaults import *
        from mysite import models, views
        
        urlpatterns = patterns('',
            (r'^events/$', views.object_list, {'model': models.Event}),
            (r'^blog/entries/$', views.object_list, {'model': models.BlogEntry}),
        )
        
        # views.py
        from django.shortcuts import render_to_response
        
        def object_list(request, model):
            obj_list = model.objects.all()
            template_name = 'mysite/%s_list.html' % model.__name__.lower()
            return render_to_response(template_name, {'object_list': obj_list})
        
    另外需要了解,在同时传递额外参数和捕捉值时,参数的优先级是大于捕捉值的
        urlpatterns = patterns('',
            (r'^mydata/(?P<id>\d+)/$', views.my_view, {'id': 3}),
        )
        对上面视图调用,传递结果一直为 /mydata/3/ 


32. 使用缺省视图参数
    可以像函数中使用默认值一样,可views中也可以指定默认的缺省参数
        # urls.py
        from django.conf.urls.defaults import *
        from mysite import views
        urlpatterns = patterns('',
            (r'^blog/$', views.page),
            (r'^blog/page(?P<num>\d+)/$', views.page),
        )
        
        # views.py
        def page(request, num='1'):
            # Output the appropriate page of blog entries, according to num.
            # ...


33. 从URL中捕获文本
    对每个被捕获的参数,将作为字符串来发送,而不管正则式中的模式
        (r'^articles/(?P<year>\d{4})/$', views.year_archive),
    其中\d{4}捕获4位的年份数值,但传递到后台时是作为字符来识别的。

        # urls.py
        from django.conf.urls.defaults import *
        from mysite import views
        urlpatterns = patterns('',
            (r'^articles/(\d{4})/(\d{2})/(\d{2})/$', views.day_archive),
        )

        # views.py
        import datetime
        def day_archive(request, year, month, day):
            date = datetime.date(year, month, day)  # 抛出TypeError错误
        因此 day_archive() 应该这样写才是正确的:
        def day_archive(request, year, month, day):
            date = datetime.date(int(year), int(month), int(day))


34. 处理请求分支
    在一个视图中同时处理GET和POST不是很好的习惯,应分开两个视图函数来处理
        # views.py
        from django.http import Http404, HttpResponseRedirect
        from django.shortcuts import render_to_response
        
        def method_splitter(request, GET=None, POST=None):
            if request.method == 'GET' and GET is not None:
                return GET(request)
            elif request.method == 'POST' and POST is not None:
                return POST(request)
            raise Http404
        
        def some_page_get(request):
            assert request.method == 'GET'
            do_something_for_get()
            return render_to_response('page.html')
        
        def some_page_post(request):
            assert request.method == 'POST'
            do_something_for_post()
            return HttpResponseRedirect('/someurl/')
        
        # urls.py
        from django.conf.urls.defaults import *
        from mysite import views
        
        urlpatterns = patterns('',
            (r'^somepage/$', views.method_splitter, 
                {'GET': views.some_page_get, 'POST': views.some_page_post}),
            # 这里是关键
            # 向函数视图传递GET或者POST时会调用不同的处理方法
        )
    
    可以使用更优雅的方法来处理请求
        def method_splitter(request, *args, **kwargs):
            get_view = kwargs.pop('GET', None)
            post_view = kwargs.pop('POST', None)
            if request.method == 'GET' and get_view is not None:
                return get_view(request, *args, **kwargs)
            elif request.method == 'POST' and post_view is not None:
                return post_view(request, *args, **kwargs)
            raise Http404


35. 包含其他URLconf
    当程序包含多个app时,可以在根urls中包含app的urls即可
        # mysite/urls.py
        from django.conf.urls.defaults import *
        
        urlpatterns = patterns('',
            (r'^weblog/', include('mysite.blog.urls')),  # 包含blog中的url
            (r'^photos/', include('mysite.photos.urls')),  # 注意url后不含$符号
            (r'^about/$', 'mysite.views.about'),
        )
        
        # mysite/bolg/urls.py
        from django.conf.urls.defaults import *
        
        urlpatterns = patterns('',
            (r'^(\d\d\d\d)/$', 'mysite.blog.views.year_detail'),
            (r'^(\d\d\d\d)/(\d\d)/$', 'mysite.blog.views.month_detail'),
        )
        
    一个被包含的URLconf,它接收任何来自父级URLconf的被捕捉参数
        # urls.py
        from django.conf.urls.defaults import *
        
        urlpatterns = patterns('',
            (r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
            # foo.urls.blog中定义的url都会捕捉到username
        )
        
    同样,子级urlconf也可以获取父级的指定参数
        # urls.py
        from django.conf.urls.defaults import *
        
        urlpatterns = patterns('',
            (r'^blog/', include('inner'), {'blogid': 3}),
            # inner中每个设置的url都会获取blogid=3这个参数
        )

posted @ 2010-04-30 09:22  听风  阅读(457)  评论(0编辑  收藏  举报