URL配置的一些技巧:
1、添加视图前缀的方法:
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、使用命名参数:
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),
)
视图进行如下匹配:
month_archive(request, year='2006', month='03')
使用命名参数顺序如下:
- 如果包含命名参数,则忽略所有未命名参数
- 如果没有,则使用顺序参数调用
- 以上两种方式中,都可以传递额外选项。
3、生成通用视图
# 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})
4、匹配特例
在通过正则表达式处理大量url请求时,可能需要对某个特定的url请求调用不同的视图处理函数。解决的方法是将需要匹配的url特例放在通用的正则表达式前,如下例:
urlpatterns = patterns('',
# ...
('^auth/user/add/$', views.user_add_stage),
('^([^/]+)/([^/]+)/add/$', views.add_stage),
# ...
)
5、包含其他URL
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'),
)
注意:包含的URL不要以$结尾!!!
6、传递额外参数
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'),
)
模板的高级技巧:
RequestContext类和Context处理器
下面通过一个例子来看一下RequestContext的使用。
from django.template import loader, Context
def view_1(request):
# ...
t = loader.get_template('template1.html')
c = Context({
'app': 'My app',
'user': request.user,
'ip_address': request.META['REMOTE_ADDR'],
'message': 'I am view 1.'
})
return t.render(c)
def view_2(request):
# ...
t = loader.get_template('template2.html')
c = Context({
'app': 'My app',
'user': request.user,
'ip_address': request.META['REMOTE_ADDR'],
'message': 'I am the second view.'
})
return t.render(c)
通过使用RequestContext,就可以简化上面的代码:
from django.template import loader, RequestContext
def custom_proc(request):
"A context processor that provides 'app', 'user' and 'ip_address'."
return {
'app': 'My app',
'user': request.user,
'ip_address': request.META['REMOTE_ADDR']
}
def view_1(request):
# ...
t = loader.get_template('template1.html')
c = RequestContext(request, {'message': 'I am view 1.'},
processors=[custom_proc])
return t.render(c)
def view_2(request):
# ...
t = loader.get_template('template2.html')
c = RequestContext(request, {'message': 'I am the second view.'},
processors=[custom_proc])
return t.render(c)
对于render_to_response()函数,我们可以使用context_instance参数:
from django.shortcuts import render_to_response
from django.template import RequestContext
def custom_proc(request):
"A context processor that provides 'app', 'user' and 'ip_address'."
return {
'app': 'My app',
'user': request.user,
'ip_address': request.META['REMOTE_ADDR']
}
def view_1(request):
# ...
return render_to_response('template1.html',
{'message': 'I am view 1.'},
context_instance=RequestContext(request, processors=[custom_proc]))
def view_2(request):
# ...
return render_to_response('template2.html',
{'message': 'I am the second view.'},
context_instance=RequestContext(request, processors=[custom_proc]))
定制模板过滤器
过滤器函数可以有一个或两个参数,第一个参数为输入,第二个参数为选项。下面来看一些例子:
def cut(value, arg):
"Removes all values of arg from the given string" return value.replace(arg, '')
{{ somevariable|cut:" " }}
def lower(value): # Only one argument. "Converts a string into all lowercase" return value.lower()
注册定制过滤器的代码如下:
from django import template
register = template.Library() register.filter('cut', cut) register.filter('lower', lower)
定制模板标签
在django中,模板系统的工作分为两部分:编译和渲染。
在编译的过程中,django会分析模板标签,并将其生成相应的django.template.Node对象,该对象中包含有render()函数。可参考下面的例子:
Hello, {{ person.name }}.
{% ifequal name.birthday today %}
Happy birthday!
{% else %}
Be sure to come back on your birthday
for a splendid surprise message.
{% endifequal %}
上面的模板在分析后,会生成如下Node列表:
- Text node: "Hello, "
- Variable node: person.name
- Text node: ".\n\n"
- IfEqual node: name.birthday and today
在编译完成后,会依次调用每个Node的render()函数进行渲染。
编译函数的编写
下面通过一个{% current_time %}标记来演示定制标签的方法。我们要实现的标签的使用方法如下:
<p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>
首先是编译函数:
from django import template
register = template.Library() def do_current_time(parser, token):
try:
# split_contents() knows not to split quoted strings. tag_name, format_string = token.split_contents() except ValueError:
msg = '%r tag requires a single argument' % token.split_contents()[0] raise template.TemplateSyntaxError(msg) return CurrentTimeNode(format_string[1:-1])
需要注意的是,在编译函数中不能抛出异常。返回的一定是一个Node的子类。
创建Node子类
下面来创建CurrentTimeNode类:
import datetime
class CurrentTimeNode(template.Node):
def __init__(self, format_string):
self.format_string = str(format_string)
def render(self, context):
now = datetime.datetime.now()
return now.strftime(self.format_string)
注册标签
注册标签的方法如下:
register.tag('current_time', do_current_time)
模型的高级应用
添加额外的管理器
# models.py
from django.db import models
# ... Author and Publisher models here ...
class BookManager(models.Manager):
def title_count(self, keyword):
return self.filter(title__icontains=keyword).count()
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
num_pages = models.IntegerField(blank=True, null=True)
objects = BookManager()
def __unicode__(self):
return self.title
使用如下:
>>> Book.objects.title_count('django')
4
>>> Book.objects.title_count('python')
18