URLconf 配置
示例一
Python
1 | urlpatterns = patterns('', |
2 | (r '^hello/$' , 'mysite.views.hello' ), |
3 | (r '^time/$' , 'mysite.views.current_datetime' ), |
4 | (r '^time/plus/(\d{1,2})/$' , 'mysite.views.hours_ahead' ), |
5 | (r '^tag/(\w+)/$' , 'weblog.views.tag' ), |
示例二
Python
1 | urlpatterns = patterns( 'mysite.views' , |
2 | (r '^hello/$' , 'hello' ), |
3 | (r '^time/$' , 'current_datetime' ), |
4 | (r '^time/plus/(\d{1,2})/$' , 'hours_ahead' ), |
7 | urlpatterns + = patterns( 'weblog.views' , |
8 | (r '^tag/(\w+)/$' , 'tag' ), |
示例三
Python
1 | urlpatterns = patterns('', |
2 | (r '^articles/(?P\d{4})/$' , views.year_archive), |
3 | (r '^articles/(?P\d{4})/(?P\d{2})/$' , views.month_archive), |
6 | urlpatterns + = patterns('', |
7 | (r '^debuginfo/$' , views.debug), |
示例四
Python
1 | urlpatterns = patterns('', |
2 | (r '^foo/$' , views.foobar_view, { 'template_name' : 'template1.html' }), |
3 | (r '^bar/$' , views.foobar_view, { 'template_name' : 'template2.html' }), |
示例五
Python
1 | urlpatterns = patterns('', |
2 | (r '^mydata/birthday/$' , views.my_view, { 'month' : 'jan' , 'day' : '06' }), |
3 | (r '^mydata/(?P\w{3})/(?P\d\d)/$' , views.my_view), |
示例六 请求分支
Python
2 | if request.method = = 'POST' : |
3 | do_something_for_post() |
4 | return HttpResponseRedirect( '/someurl/' ) |
5 | elif request.method = = 'GET' : |
7 | return render_to_response( 'page.html' ) |
Python
01 | from django.http import Http404, HttpResponseRedirect |
02 | from django.shortcuts import render_to_response |
04 | def method_splitter(request, GET = None , POST = None ): |
05 | if request.method = = 'GET' and GET is not None : |
07 | elif request.method = = 'POST' and POST is not None : |
11 | def some_page_get(request): |
12 | assert request.method = = 'GET' |
13 | do_something_for_get() |
14 | return render_to_response( 'page.html' ) |
16 | def some_page_post(request): |
17 | assert request.method = = 'POST' |
18 | do_something_for_post() |
19 | return HttpResponseRedirect( '/someurl/' ) |
23 | from django.conf.urls.defaults import * |
24 | from mysite import views |
26 | urlpatterns = patterns('', |
28 | (r '^somepage/$' , views.method_splitter, { 'GET' : views.some_page_get, 'POST' : views.some_page_post}), |
示例七
Python
02 | if not request.user.is_authenticated(): |
03 | return HttpResponseRedirect( '/accounts/login/' ) |
04 | return render_to_response( 'template1.html' ) |
06 | if not request.user.is_authenticated(): |
07 | return HttpResponseRedirect( '/accounts/login/' ) |
08 | return render_to_response( 'template2.html' ) |
10 | if not request.user.is_authenticated(): |
11 | return HttpResponseRedirect( '/accounts/login/' ) |
12 | return render_to_response( 'template3.html' ) |
13 | def requires_login(view): |
14 | def new_view(request, * args, * * kwargs): |
15 | if not request.user.is_authenticated(): |
16 | return HttpResponseRedirect( '/accounts/login/' ) |
17 | return view(request, * args, * * kwargs) |
19 | - - - - - - - - - - - - - - - - - - - - - - - - - - |
20 | urlpatterns = patterns('', |
21 | (r '^view1/$' , requires_login(my_view1)), |
22 | (r '^view2/$' , requires_login(my_view2)), |
23 | (r '^view3/$' , requires_login(my_view3)), |
示例八:include()
被捕获的 username 变量将传递给被包含的 URLconf,进而传递给那个URLconf中的 每一个 视图函数。
Python
01 | from django.conf.urls.defaults import * |
02 | urlpatterns = patterns('', |
03 | (r '^(?P\w+)/blog/' , include( 'foo.urls.blog' ) ,{ 'blogid' : 3 }), |
06 | from django.conf.urls.defaults import * |
07 | urlpatterns = patterns('', |
08 | (r '^$' , 'foo.views.blog_index' ), |
09 | (r '^archive/$' , 'foo.views.blog_archive' ), |
模板
django.template.RequestContext
RequestContext 默认地在模板context中加入了一些变量,如 HttpRequest 对象或当前登录用户的相关信息。 当你不想在一系例模板中都明确指定一些相同的变量时,你应该使用 RequestContext
全局模板变量
不论它们存放在哪个物理路径下,只要在你的Python搜索路径中,你就可以在 TEMPLATE_CONTEXT_PROCESSORS 设置里指向它们。 建议你把它们放在应用或者工程目录下名为 context_processors.py 的文件里。
默认的
Python
1 | TEMPLATE_CONTEXT_PROCESSORS = ( |
2 | 'django.core.context_processors.auth' , |
3 | 'django.core.context_processors.debug' , |
4 | 'django.core.context_processors.i18n' , |
5 | 'django.core.context_processors.media' , |
可添加 django.core.context_processors.request
custom_proc: TEMPLATE_CONTEXT_PROCESSORS = (mysite.下面的文件名.custom_proc)
Python
01 | from django.shortcuts import render_to_response |
02 | from django.template import RequestContext |
04 | def custom_proc(request): |
05 | "A context processor that provides 'app', 'user' and 'ip_address'." |
09 | 'ip_address' : request.META[ 'REMOTE_ADDR' ] |
14 | return render_to_response( 'template1.html' , |
15 | { 'message' : 'I am view 1.' }, |
16 | context_instance = RequestContext(request, processors = [custom_proc])) |
20 | return render_to_response( 'template2.html' , |
21 | { 'message' : 'I am the second view.' }, |
22 | context_instance = RequestContext(request, processors = [custom_proc])) |
关闭模板自动转意: {{ data|safe }}
{% autoescape off %}
Hello {{ name }}
{% endautoescape %}
auto-escaping 标签的作用域不仅可以影响到当前模板还可以通过include标签作用到其他标签,就像block标签一样。
过滤器参数里的字符串常量的自动转义:{{ data|default:"3 < 2" }}
扩展模板系统:http://djangobook.py3k.cn/2.0/chapter09/
数据模型
http://djangobook.py3k.cn/2.0/chapter10/
访问外键(Foreign Key)值
Python
1 | from mysite.apptest.models import Book |
2 | b = Book.objects.get( id = 50 ) |
4 | p = Publisher.objects.get(name = 'Apress1' ) |
访问多对多值(Many-to-Many Values)
多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例
Python
1 | b = Book.objects.get( id = 1 ) |
增加额外的Manager方法 我们为Book模型定义了一个title_count()方法
Python
1 | class BookManager(models.Manager): |
2 | def title_count( self , keyword): |
3 | return self . filter (title__icontains = keyword).count() |
Python
1 | class Book(models.Model): |
2 | title = models.CharField(max_length = 100 ) |
3 | authors = models.ManyToManyField(Author) |
4 | publisher = models.ForeignKey(Publisher) |
5 | publication_date = models.DateField() |
6 | objects = BookManager() |
模型方法与属性: 执行原始SQL查询
connection和cursor几乎实现了标准Python DB-API
Python
1 | >>> from django.db import connection |
2 | >>> cursor = connection.cursor() |
7 | >>> row = cursor.fetchone() |
通用视图
呈现静态“关于”页面的URLconf
Python
2 | from django.conf.urls.defaults import * |
3 | from django.views.generic.simple import direct_to_template |
5 | urlpatterns = patterns('', |
6 | (r '^about/$' , direct_to_template, { 'template' : 'about.html' }) |
7 | (r '^about/(\w+)/$' , about_pages), |
对象的通用视图
Python
01 | from django.conf.urls.defaults import * |
02 | from django.views.generic import list_detail |
03 | from apptest.apptest.models import Publisher |
05 | return Book.objects. all () |
08 | 'queryset' : Publisher.objects. all (), |
09 | 'template_name' : 'publisher_list_page.html' , |
10 | 'template_object_name' : 'publisher' , |
12 | extra_context ': {' book_list': get_books} |
17 | urlpatterns = patterns('', |
18 | (r '^publishers/$' , list_detail.object_list, publisher_info) |
扩展通用视图
用函数包装来处理复杂的数据过滤
Python
01 | from django.shortcuts import get_object_or_404 |
02 | from django.views.generic import list_detail |
03 | from mysite.apptest.models import Book, Publisher |
04 | def books_by_publisher(request, name): |
06 | publisher = get_object_or_404(Publisher, name__iexact = name) |
09 | return list_detail.object_list( |
11 | queryset = Book.objects. filter (publisher = publisher), |
12 | template_name = 'books/books_by_publisher.html' , |
13 | template_object_name = 'book' , |
14 | extra_context = { 'publisher' : publisher} |
处理额外工作
修改视图返回值
Python
01 | def author_detail(request, author_id): |
03 | response = list_detail.object_detail( |
05 | queryset = Author.objects. all (), |
06 | object_id = author_id, |
08 | now = datetime.datetime.now() |
09 | Author.objects. filter ( id = author_id).update(last_accessed = now) |
文件下载:Content-Disposition 的含义是 告诉浏览器下载并保存这个页面
Python
1 | def author_list_plaintext(request): |
2 | response = list_detail.object_list( |
4 | queryset = Author.objects. all (), |
5 | mimetype = 'text/plain' , |
6 | template_name = 'books/author_list.txt' |
8 | response[ "Content-Disposition" ] = "attachment; filename=authors.txt" |
输出非HTML内容
视图和MIME类型
Python
1 | from django.http import HttpResponse |
4 | image_data = open ( "/path/to/my/image.png" , "rb" ).read() |
5 | return HttpResponse(image_data, mimetype = "image/png" ) |
生成 CSV 文件
响应返回的是 text/csv MIME类型(而非默认的 text/html )。这会告诉浏览器,返回的文档是CSV文件。
Python
02 | from django.http import HttpResponse |
06 | UNRULY_PASSENGERS = [ 146 , 184 , 235 , 200 , 226 , 251 , 299 , 273 , 281 , 304 , 203 ] |
08 | def unruly_passengers_csv(request): |
10 | response = HttpResponse(mimetype = 'text/csv' ) |
11 | response[ 'Content-Disposition' ] = 'attachment; filename=unruly.csv' |
14 | writer = csv.writer(response) |
15 | writer.writerow([ 'Year' , 'Unruly Airline Passengers' ]) |
16 | for (year, num) in zip ( range ( 1995 , 2006 ), UNRULY_PASSENGERS): |
17 | writer.writerow([year, num]) |
生成 PDF 文件 安装 ReportLab: http://www.reportlab.org/downloads.html.
Python
01 | from reportlab.pdfgen import canvas |
02 | from django.http import HttpResponse |
04 | def hello_pdf(request): |
06 | response = HttpResponse(mimetype = 'application/pdf' ) |
07 | response[ 'Content-Disposition' ] = 'attachment; filename=hello.pdf' |
10 | p = canvas.Canvas(response) |
14 | p.drawString( 100 , 100 , "Hello world." ) |
需要注意以下几点:
这里我们使用的 MIME 类型是 application/pdf 。这会告诉浏览器这个文档是一个 PDF 文档,而不是 HTML 文档。 如果忽略了这个参数,浏览器可能会把这个文件看成 HTML 文档,这会使浏览器的窗口中出现很奇怪的文字。 If you leave off this information, browsers will probably interpret the response as HTML, which will result in scary gobbledygook in the browser window.
使用 ReportLab 的 API 很简单: 只需要将 response 对象作为 canvas.Canvas 的第一个参数传入。
所有后续的 PDF 生成方法需要由 PDF 对象调用(在本例中是 p ),而不是 response 对象。
最后需要对 PDF 文件调用 showPage() 和 save() 方法(否则你会得到一个损坏的 PDF 文件)。
复杂的 PDF 文件
如果您在创建一个复杂的 PDF 文档(或者任何较大的数据块),请使用 cStringIO 库存放临时生成的 PDF 文件。 cStringIO 提供了一个用 C 编写的类似文件对象的接口,从而可以使系统的效率最高。 下面是使用 cStringIO 重写的 Hello World 例子
Python
01 | from cStringIO import StringIO |
02 | from reportlab.pdfgen import canvas |
03 | from django.http import HttpResponse |
05 | def hello_pdf(request): |
07 | response = HttpResponse(mimetype = 'application/pdf' ) |
08 | response[ 'Content-Disposition' ] = 'attachment; filename=hello.pdf' |
13 | p = canvas.Canvas(temp) |
17 | p.drawString( 100 , 100 , "Hello world." ) |
24 | response.write(temp.getvalue()) |
其它文件类型
ZIP 文件 :Python 标准库中包含有 zipfile 模块,它可以读和写压缩的 ZIP 文件。 它可以用于按需生成一些文件的压缩包,或者在需要时压缩大的文档。
动态图片 : Python 图片处理库 (PIL; http://www.pythonware.com/products/pil/) 是极好的生成图片(PNG, JPEG, GIF 以及其它许多格式)的工具。 它可以用于自动为图片生成缩略图,将多张图片压缩到单独的框架中,或者是做基于 Web 的图片处理。
图表 :matplotlib (http://matplotlib.sourceforge.net/) 可以用于生成通常是由 matlab 或者 Mathematica 生成的高质量图表。
pygraphviz (https://networkx.lanl.gov/wiki/pygraphviz) 是一个 Graphviz 图形布局的工具 (http://graphviz.org/) 的 Python 接口,可以用于生成结构化的图表和网络。
内容聚合器应用框架
RSS和Atom都是基于XML的格式,你可以用它来提供有关你站点内容的自动更新的feed
http://djangobook.py3k.cn/2.0/chapter13/
会话、用户和注册
Cookies
Python
1 | def show_color(request): |
2 | request.COOKIES[ "favorite_color" ] |
3 | response.set_cookie( "favorite_color" ,request.GET[ "favorite_color" ]) |
可选的参数: 参数, 缺省值, 描述
max_age, None, cookie需要延续的时间(以秒为单位)cookie将持续,直到浏览器关闭。
expires, None, cookie失效的实际日期/时间,格式 "Wdy, DD-Mth-YY HH:MM:SS GMT" 此参数将覆盖max_age参数。
path, /, cookie, 生效的路径,特别用天当你无法控制网站的顶级域名。
domain, None, cookie有效的域名, 例 domain=".example.com" 指 *.example.com
secure, false, 如果设置为True, 则指定使用 https 的方式来访问这个cookie
设置测试Cookies: request.session.set_test_cookie(),test_cookie_worked(),delete_test_cookie()
Sessions
Sessions在Django中是一个字典型的对象:如 keys() 和 items() 对 request.session 同样有效
Session字典中以下划线开头的key值是Django内部保留key值。
不要用一个新对象来替换掉 request.session ,也不要存取其属性。
打开sessions功能
编辑 MIDDLEWARE_CLASSES 配置,确保 MIDDLEWARE_CLASSES 中包含 'django.contrib.sessions.middleware.SessionMiddleware'。
确认 INSTALLED_APPS 中有 'django.contrib.sessions' (如果你是刚打开这个应用,别忘了运行 manage.py syncdb )
在视图中使用Session
Python
1 | request.session[ "fav_color" ] = "blue" |
2 | fav_color = request.session[ "fav_color" ] |
3 | del request.session[ "fav_color" ] |
4 | if "fav_color" in request.session: |
在视图(View)外使用Session:使用Django数据库API来存取session
Python
1 | from django.contrib.sessions.models import Session |
2 | s = Session.objects.get(pk = '2b1189a188b44ad18c35e113ac6ceead' ) |
你需要使用get_decoded() 来读取实际的session数据。 这是必需的,因为字典存储为一种特定的编码格式。
Python
2 | 'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...' |
何时会自动保存Session:session_data字典赋值或删除
浏览器关闭即失效会话 vs 持久会话
改变 SESSION_EXPIRE_AT_BROWSER_CLOSE 的设置来控制session自动过期
缺省情况下, SESSION_EXPIRE_AT_BROWSER_CLOSE 设置为 False ,这样,会话cookie可以在用户浏览器中保持有效达 SESSION_COOKIE_AGE 秒(缺省设置是两周,即1,209,600 秒)
如果 SESSION_EXPIRE_AT_BROWSER_CLOSE 设置为 True ,当浏览器关闭时,Django会使cookie失效。
其他的Session设置
SESSION_COOKIE_DOMAIN, 使用会话cookie(session cookies)的站点。 将它设成一个字符串,就好象`` “.example.com”`` 以用于跨站点(cross-domain)的cookie,或`` None`` 以用于单个站点。
SESSION_COOKIE_NAME, 会话中使用的cookie的名字。 它可以是任意的字符串。 如:"sessionid"
SESSION_COOKIE_SECURE, 是否在session中使用安全cookie。 如果设置 True , cookie就会标记为安全, 这意味着cookie只会通过HTTPS来传输。