Django绝对简明手册(写作中)
Contents
张沈鹏 电子科技大学 生物医学工程/计算机科学与技术 你看到的此文档,可能不是最新的, 欢迎访问我的 Blog 了解最新的变化. 也欢迎加入我的Google讨论群, 讨论一切关于 C++,STL,Boost, XML,CSS,Javascript,XUL Python,Django 的问题
-- Any Question,Please Email To [email protected]
更新:2007.6 beta
- Django版本:9.6
- Python版本:2.5
1. 序言
现在学的东西很容易忘记,写这篇文章的目的是能让我在需要时快速找回当时的感觉. Find Fun !
内容大部分摘自hideto翻译的Django Book,在此感谢
2. 辅助工具
文本替换专家2.5 : 修改站名,APP模块名时用得到
3. View函数
向浏览器输出html等的函数.
3.1. 直接输出
from django.http import HttpResponse import datetime #View函数的第一个参数总是HttpRequest对象 #offset是一个string,值由url正则表达式匹配而得。 def hours_ahead(request, offset): offset = int(offset) dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = "In %s hour(s), it will be %s." % (offset, dt) return HttpResponse(html)
3.2. 泛型视图
3.2.1. 渲染模板
django.views.generic.simple.direct_to_template
渲染一个给定的模板,并把在URL里捕获的参数组成字典作为{{ params }}模板变量传递给它
(r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template': 'foo_detail.html'}),
3.2.2. 重定向到另一URL
#如果url对应的是None则返回410 HTTP(不可用)错误 ('^foo/(?p<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
3.2.3. 复杂视图概览
- List/detail视图,它提供对象列表和单独对象细节的页面(例如地点列表和单独的一个地点的信息页面)
- Date-based视图,它提供year/month/day样式的以日期为中心的信息页面
- Create/update/delete视图,它允许你快速创建增,删,改对象的视图
通用的可选参数
- allow_empty
一个布尔值,指定没有对象时是否显示页面,如果它是False并且没有对象,视图将触发404错误而不是显示空页面,默认是False
- context_processors
一个视图模板的template-context processors列表,参考第10章得到更多template context processors的信息
- extra_context
一个添加到模板context的字典值,它默认为空字典,如果字典中的一个值可以调用,generic view将在渲染模板前调用它
- mimetype
用来生成结果文档的MIME类型,默认为DEFAULT_MIME_TYPE设置的值
- template_loader
当载入模板时使用的模板载入器,默认为django.template.loader
- template_name
渲染页面时使用的完整的模板名,它可以让你覆盖来自于QuerySet的默认模板名
- template_object_name
指定在模板context中的模板变量名,默认为'object',视图列表列出不止一个对象时将在此变量值后添加'_list'
3.2.4. 显示+分页object_list
django.views.generic.list_detail.object_list视图用来创建一个显示对象列表的页面
from django.conf.urls.defaults import * from django.views.generic import list_detail, date_based, create_update from bookstore.models import Publisher, Author, Book author_list_info = { 'queryset' : Author.objects.all(), 'allow_empty': True, } urlpatterns = patterns('', (r'authors/$', list_detail.object_list, author_list_info) , )
我们只需为generic view制作一个模板来渲染即可 可选的参数:
paginate_by
你个指出每一页多少对象应该被显示的整数,如果这项被给定,视图将使用paginate_by分页视图将希望得到一个包含了从零开始索引页数的page查询字符串参数(通过GET),或者一个在URL配置里指定的page变量.
template_name: 模板名没有被指定,视图将默认使用(app_label)/(model_name)_list.html.
app标签和模型名字两者都来自于queryset参数,app标签是模型定义所在的app的名字,模型名字则是模型类的名字的小写版本
所以当我们把Author.objects.all()作为queryset传递时,app标签将是bookstore,模型名则是author
这意味着默认的模板将是bookstore/author_list.html
模板context
除了extra_context,模板的context将包括:
object_list
对象的列表,这个变量的名字取决于template_object_name参数,而后者默认是'object' 如果template_object_name是'foo',则这个变量的名字就是foo_list
is_paginated
一个boolean值,它表示结果是否分页
特别的,当可得到的对象的数量小于或等于paginate_by时,它的值被设为False
如果结果是分页的,context将包含以下额外变量
results_per_page 每页对象的数量(和paginate_by参数一样)
has_next 一个boolean值,它表示是否有下一页
has_previous 一个boolean值,它表示是否有上一页
page 当前页的页数,它是一个整数,从1开始
next 下一页的页数,它是一个整数,如果没有下一页,它还是一个整数并表示理论上的下一页页数,从1开始
previous 上一页的页数,它是一个整数,从1开始
pages 总页数,它是一个整数
hits 所有页面的对象的总数,不仅仅是当前页
3.2.5. 细节视图object_detail
像下面这样提供一个info字典:
author_detail_info = { "queryset" : Author.objects.all(), "template_object_name" : "author", }
URL模式如下
(r'^authors/(?P<object_id>\d+)/$', list_detail.object_detail, author_detail_info),
必需的参数
queryset
object_id
或者
slug
slug_field 对象中包含slug的域的名字,如果你使用slug参数,则它是必需的,如果你使用object_id参数则不能要
template_name_field 如果你的对象有一个'the_template'域(属性)并且该域包含一个字符串'foo.html',你把template_name_field设置为the_template,则这个对象的generic view将使用模板'foo.html'
除了extra_context,模板的context是
object
对象,这个变量的名字取决于template_object_name参数,默认是'object',如果template_object_name是'foo',这个变量的名字就是foo
3.2.6. 日期显示最近
django.views.generic.date_based_archive_index视图提供了一个通过日期显示最近的对象的顶级首页 一个典型的publisher可能想把最近发表的books设为语法高亮,我们可以使用archive_index视图来做这件事,下面是info dict
book_info = { "queryset" : Book.objects.all(), "date_field" : "publication_date" }
相应的URL配置: (r'^books/$', date_based.archive_index, book_info)
必需的参数:
date_field 在QuerySet的模型中的DateField或者DateTimeField的名字,基于日期的存档使用它来决定页面上的对象
queryset 存档处理的QuerySet的对象
可选参数:
allow_future 一个布尔值,它指定是否在这个页面引入"未来"的对象
num_latest 传递到模板context的最近的对象数目,默认为15 模板的context为如下列表:
date_list datetime.date对象的列表,表示对应queryset的所有具有对象的years,他们排反序
例如,如果你有一个从2003到2006的blog列表,这个列表将包含4个datetime.date对象:每年一个latest
系统中的num_latest个对象,通过date_field排倒序
例如如果num_latest为10,latest将为queryset中的最近的10个对象
4. Url
4.1. 匹配参数
(r'^now/plus\d+hours/$', hours_ahead)
可以匹配
/now/plus2hours/ /now/plus125hours/ /now/plus100000000000hours/
限制最多99小时,即只允许1个或2个数字
(r'^now/plus(\d{1,2})hours/$', hours_ahead)
4.2. 常用正则式
. 任意字符 \d 任意数字 [A-Z] 从A到Z的任意字符(大写) [a-z] 从a到z的任意字符(小写) [A-Za-z] 从a到z的任意字符(大小写不敏感) [^/]+ 任意字符直到一个前斜线(不包含斜线本身) + 一个或多个前面的字符 ? 零个或多个前面的字符 {1,3} 1个到3个之间前面的字符(包括1和3)
4.3. 命名变量
传给函数以year命名的变量
(r'^articles/(?P<year>\d{4})/$', views.year_archive),
4.4. 指定参数
传递参数,动态选择模板,有时配合默认参数会很方便 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})
4.5. include URL配置
注意:指向inclue()的正则表达式不包含$(字符串结尾匹配符),但包含一个末尾斜线
(r'^photos/', include('mysite.photos.urls')),
include时可以附加额外的参数
#额外选项将一直传递给include的URL配置的每一行,仅当你确认在include的URL配置里每个视图接受你传递的选项时才有意义 (r'^blog/', include('inner'), {'blogid': 3}),
5. 模版
5.1. 传入参数
from django.template import Context, Template t = Template("My name is {{name}}.") c = Context({"name": "Stephane"}) t.render(c)
输出
'My name is Stephane.'
渲染的对象还可以是,字典
person = {'name': 'Sally', 'age': '43'}
对应的模板为
{{ person.name }} is {{ person.age }} years old.'
类
class Person(object): def __init__(self,first_name,last_name): self.first_name, self.last_name = first_name, last_name
对于的模板和上面类似
对于类似 Contexst({'items': ['apples', 'bananas', 'carrots']}) 的数组 items.2就表示carrots
默认情况下如果变量不存在,模板系统会把它渲染成空string
5.2. 调用对象的方法
如对于Context({'var': '123ss'})可以在模板中用var.upper来调用upper()方法,被调用的方法不能有参数
如果一个方法触发了异常,会致渲染失败.
如果异常有一个值为True的silent_variable_failure属性,这个变量会渲染成空string
class SilentAssetionError(AssertionError): silent_variable_failure = True class PersonClass4: def first_name(self): raise SilentAssertionError p = PersonClass4() #将被渲染为空字串 t.render(Context({"person": p}))
设置方法的alters_data属性为true可以禁止在模板中调用该方法
def delete(self): pass delete.alters_data = True
5.3. 插入变量
<p>Sincerely,<br />{{ 变量名 }}</p>
5.4. 块语句
5.4.1. if
{% if %}标签不允许同一标签里同时出现and和or
可以使用嵌套的{% if %}来表示and和or
{%if xxx%} <p>内容1</p> {%else%} <p>内容2</p> {%endif%}
5.4.2. ifequal/ifnotequal
{% ifequal user currentuser %} <h1>Welcome!</h1> {% endifequal %}
参数可以是硬编码的string,数字等,如{% ifequal section 'sitenews' %},{% ifequal section 1.3 %}
5.4.3. for
{% for %}标签允许你按顺序遍历一个序列中的各个元素
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>
在标签里添加reversed来反序循环列表,如{% for athlete in athlete_list reversed %}
{% for %}标签内置了一个forloop变量
- forloop.counter表示循环的次数,从1开始计数
- forloop.counter0类似于forloop.counter,但它是从0开始计数
- forloop.revcounter表示循环中剩下的items数量,第一次循环时设为items总数,最后一次设为1
- forloop.revcounter0类似于forloop.revcounter,但它是表示的数量减一,即最后一次循环时设为0
- forloop.first当第一次循环时值为True,在特别情况下很有用
{% for object in objects %} {% if forloop.first %}<li class="first">{% else %}<li>{% endif %} {{ object }} </li> {% endfor %}
- forloop.last当最后一次循环时值为True
- forloop.parentloop在嵌套循环中表示父循环的forloop
5.4.4. include
{% include 'includes/nav.html' %}
如果给定的模板名不存在,Django将做下面两件事情中的一件:
1,如果DEBUG设置为True,你将看到一个TemplateDoesNotExist异常的错误页面
2,如果DEBUG设置为False,标签将什么也不显示
5.4.5. 注释
{# This is a comment #} 模板渲染时注释不会输出,一个注释不能分成多行
5.4.6. 使用模板文件
from django.template.loader import get_template from django.template import Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() t = get_template('current_datetime.html') html = t.render(Context({'current_date': now})) return HttpResponse(html)
或者更直接
from django.shortcuts import render_to_response import datetime def current_datetime(request): now = datetime.datetime.now() return render_to_response('current_datetime.html', {'current_date': now})
如果你很懒或者你想保持代码整洁,使用Python内建的locals()方法返回一个包含当前作用域里面的所有变量和它们的值的字典
locals()导致了一点点开销,因为Python不得不动态创建字典,如果你手动指定context字典则可以避免这项开销
def current_datetime(request): current_date = datetime.datetime.now() return render_to_response('current_datetime.html', locals())
5.5. 过滤器
5.5.1. date
把ship_date变量传递给过滤器,并给date过滤器传递了一个参数“F j, Y”,date过滤器以给定参数的形式格式化日期
{{ship_date|date:"F j, Y"}}
5.5.2. escape / linebreaks
escape转义给定的string里出现的&符,引号,尖括号
常用于处理用户提交的数据和确认合法的XML和XHTML数据
escape文本内容然后把换行转换成p标签
{{ my_text|escape|linebreaks }}
显示bio变量的前30个字,过滤器参数一直使用双引号
{{ bio|truncatewords:"30" }}
5.5.3. addslashed
在任何后斜线,单引号,双引号前添加一个后斜线,常用于输出文本到JavaScript字符串
5.5.4. length
返回值的长度,你可以在一个list或string上做此操作
6. Model数据库
from django.db import models class Author(models.Model): name = models.CharField(maxlength=30) headshot = models.ImageField(upload_to='/tmp') email = models.EmailField() def __str__(self): return self.name class Publisher(models.Model): website = models.URLField() class Book(models.Model): authors = models.ManyToManyField(Author) #多对多 publisher = models.ForeignKey(Publisher) #1对1 publication_date = models.DateField()
属性名对应列名
属性的类型(如CharField)对应数据库列类型
除非你自己定义一个主键,Django会自动为每个模型生成一个integer主键域id
每个Django模型都必须有一个单列的主键
p = Publisher(website='http://www.apress.com/') p.save() publisher_list = Publisher.objects.all()