django系统学习笔记~~(7)高级视图和URL配置

(6)http://hi.baidu.com/derris/blog/item/e8ee10fafd711915a9d31185.html
(8)http://hi.baidu.com/derris/blog/item/f490f213dc314f095baf53cc.html

urls.py文件中提供的入口函数导入格式,相对复杂。

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

有一种相对简洁的写法,这样起码不用再写2边:
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'),
)
还可以更好的处理一下,在第一个参数中声明好导入模块。
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
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'),
)

可以声明调试模式,提供一些参数信息:

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:
    urlpatterns += patterns('',
        (r'^debuginfo/$', views.debug),
    )

django自动根据正则表达式匹配对应的函数调用,对于函数参数,有2种传递方式:
按顺序的匿名参数传递和指定参数名字的传递方式,如:
urlpatterns = patterns('',
    (r'^articles/(\d{4})/$', views.year_archive),
    (r'^articles/(\d{4})/(\d{2})/$', views.month_archive),
) 产生函数调用:month_archive(request, '2006', '03')

urlpatterns = patterns('',
    (r'^articles/(?P<year>\d{4})/$', views.year_archive),
    (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive),
) 产生函数调用:month_archive(request, year='2006', month='03')
注意在同一个模式中是不能2者混用的。

urlpattern甚至能够传递一个字典参数:
urlpatterns = patterns('',
    (r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}),
    (r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}),
)
这样对应的处理。注意参数名字和字典的主键必须一致起来就可以,参数类型可以任意。最好加上参数的默认值,就会灵活很多。
def foobar_view(request, template_name=‘default’):
    m_list = MyModel.objects.filter(is_new=True)
    return render_to_response(template_name, {'m_list': m_list})

注意:参数的数值优先于patter匹配的数值,就是说,比如
在(r'^mydata/(?P<id>\d+)/$', views.my_view, {'id': 3})看来,
对于/mydata/2/ 或者 /mydata/432432/) id这个变量都会为3。
模式匹配是有优先原则的,就是django会按照第一个能匹配的进行处理。

这样我们就可以写一个几乎能适应所有情况的一个固定模式的view处理函数:

# 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})
这样只要编辑好对应的model就可以了~!然后需要改动的只有urls.py文件和对应的模型,在views中的处理都是一样的。
由于request的请求一般分为post和get的,而且会有跟着参数,我们写一个比较通用的处理函数:# views.py

from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render_to_response

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

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}),
    # ...
)
参数*args和和**kwargs(注意*号) 这是一个Python特性,允许函数接受动态的、可变数量的、参数名只在运行时可知的参数。 如果你在函数定义时,只在参数前面加一个*号,

所有传递给函数的参数将会保存为一个元组. 如果你在函数定义时,在参数前面加两个*号,所有传递给函数的关键字参数,将会保存为一个字典 
最后处理一个重复代码的例子:假设每个函数都要验证用户,我们这样处理一下就好了:
def requires_login(view):
    def new_view(request, *args, **kwargs):
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/accounts/login/')
        return view(request, *args, **kwargs)
    return new_view
函数requires_login,传入一个视图函数view,然后返回一个新的视图函数new_view.这个新的视图函数new_view在函数requires_login内定义

处理request.user.is_authenticated()这个验证,从而决定是否执行原来的view函数 from django.conf.urls.defaults import *
from mysite.views import requires_login, my_view1, my_view2, my_view3

urlpatterns = patterns('',
    (r'^view1/$', requires_login(my_view1)),
    (r'^view2/$', requires_login(my_view2)),
    (r'^view3/$', requires_login(my_view3)),
)

关于url的包含可以写的更具有模块性一点,比如前面我们学的amdin模块的添加。如:

urlpatterns = patterns('',
    (r'^weblog/', include('mysite.blog.urls')),
    (r'^photos/', include('mysite.photos.urls')),
    (r'^about/$', 'mysite.views.about'),
)
他会根据指定目录下面对应方法进行处理。如(r'^admin/', include(admin.site.urls)),碰到admin,django会截断后面的内容,发送给admin.site.urls方法中对应的pattern进行处理。

最后注意的是inlcude包含在父urls捕获的变量或者声明的变量,会自动传递给所有的下级视图处理函数。不处理也可以~~

 


分享到: 微信 更多