Differences between revisions 1 and 16 (spanning 15 versions)
Revision 1 as of 2006-10-25 15:02:30
Size: 49300
Editor: zuroc
Comment:
Revision 16 as of 2007-06-08 18:59:32
Size: 16143
Editor: zuroc
Comment:
Deletions are marked like this. Additions are marked like this.
Line 9: Line 9:
张沈鹏 电子科技大学大三 生物医学工程 张沈鹏 电子科技大学 生物医学工程/计算机科学与技术
Line 20: Line 20:
[http://www.cppblog.com/zuroc 我的C++Blog]
[http://www.cnweblog.com/zuroc/ 我的文学Blog]
[http://zsp.javaeye.com 我的Blog]
Line 25: Line 24:
更新:2006.10 beta
Django版本:9.5
Python版本:2.5

参考:
Django Step by Step 作者: limodou
= 序言 =
更新:2007.6 beta
 * Django版本:9.6
 * Python版本:2.5
== 序言 ==
Line 35: Line 31:
本文可以作为复习资料,不宜初学.
Line 38: Line 33:
= 辅助工具 = == 辅助工具 ==
Line 41: Line 36:

= 数据库 =
== 数据库字段的类型 ==
* AutoField
* BooleanField
* CharField
* CommaSeparatedIntegerField
* DateField
* DateTimeField
* EmailField
* FileField
* FilePathField
* FloatField
* ImageField
* IntegerField
* IPAddressField
* NullBooleanField
* PhoneNumberField
* PositiveIntegerField
* PositiveSmallIntegerField
* SlugField
* SmallIntegerField
* TextField
* TimeField
* URLField
* USStateField
* XMLField

== 定义对象model-数据库映射 ==
{{{
class Blog(models.Model):
    name = models.CharField(maxlength=100)
    tagline = models.TextField()

    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(maxlength=50)
    email = models.URLField()

    def __str__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(maxlength=255)
    body_text = models.TextField()
    pub_date = models.DateTimeField()
    authors = models.ManyToManyField(Author)

    def __str__(self):
        return self.headline
}}}

== INSERT/UPDATE==
如果对象不存在,则为INSERT,存在则为UPDATE,存在与否是由 主键 判断的.

进行save()操作时才真正修改了数据库
{{{
from mysite.blog.models import Blog
b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()
}}}

== 自动增长的主键(Auto-incrementing primary keys) ==
字段名 AutoField

 当你调用save()时会自动计算它的值,如果你不用primary_key=True来手动指定一个主键,则model会自动创建一个名为id的AutoField作为主键
{{{
b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
b2.id # Returns None, because b doesn't have an ID yet.
b2.save()
b2.id # Returns the ID of your new object.
}}}

你也可以手动指定一个auto-primary-key的主键
{{{
b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.')
b3.id # Returns 3.
b3.save()
b3.id # Returns 3.
}}}
当已经存在相同的该键值时,则会覆盖原有项.

一般只有在有大量的数据时才会手动指定auto-primary-key的值,但是你要确保它们不会冲突


== 读取对象集 ==
先构造一个集合(QuerySet)来映射你在数据库中的数据.它可以有0个到很多个filter
(过滤器)-- 来缩小所表示的记录的范围.

QuerySet想当于SQL中的SELECT, filter相对应的是WHERE或者LIMIT.

用模型管理器(model Manager)可以获得QuerySet对象,一个模型至少有一个模型管理器,默认的名字是objects.访问方式如下:
{{{
# <django.db.models.manager.Manager object at ...>
#这里返回的QuerySet相当于根目录,而不是根目录中的内容
Blog.objects

b = Blog(name='Foo', tagline='Bar')
# AttributeError: "Manager isn't accessible via Blog instances."
# (不可以由实例访问)
b.objects
}}}
为了区别 表(table) 和 记录(record) , 你不可以由实例访问模型管理器.

调用模型管理器的all()就可以获得模型中所有对象QuerySet
{{{
all_entries = Entry.objects.all()
}}}

== 条件读取对象集 ==
你需要用filter(过滤器)来构造QuerySet

最常用的方式

filter(**kwargs) 包含符合条件的记录

exclude(**kwargs) 排除符合条件的记录

参数 (**kwargs) 格式如下
{{{
Entry.objects.filter(pub_date__year=2006)
}}}

多重filter
{{{
Entry.objects.filter(
 headline__startswith='What'
 ).exclude(
     pub_date__gte=datetime.now()
 ).filter(
            pub_date__gte=datetime(2005, 1, 1)
 )
}}}
结果为所有以"What"开头,在今天和2005年1月1日出版的记录.

每次过滤QuerySet都会返回一个新的QuerySet,原有的QuerySet不受影响
{{{
q1 = Entry.objects.filter(headline__startswith="What")

#q1不变
q2 = q1.exclude(pub_date__gte=datetime.now())
q3 = q1.filter(pub_date__gte=datetime.now())
}}}

== 获取对象 ==
有如下方式从QuickSet中获得对象(不获取对象时,QuickSet没有真正进行查询)
        * iterator 迭代器
{{{
          for e in Entry.objects.all():
              print e.headline
}}}

        * Slice 切片

        * repr()
== View函数 ==
向浏览器输出html等的函数.
=== 直接输出 ===
{{{
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)
}}}

=== 泛型视图 ===
==== 渲染模板 ====

django.views.generic.simple.direct_to_template

渲染一个给定的模板,并把在URL里捕获的参数组成字典作为{{ params }}模板变量传递给它
{{{
(r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template': 'foo_detail.html'}),
}}}

==== 重定向到另一URL ====
{{{
#如果url对应的是None则返回410 HTTP(不可用)错误
('^foo/(?p<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
}}}

==== 更复杂的简介 ====
 * 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'

==== 显示+分页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 所有页面的对象的总数,不仅仅是当前页

==== 细节视图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

==== 日期显示最近 ====
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个对象

== Url ==
==== 匹配参数 ====
{{{
(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)
}}}

==== 常用正则式 ====
{{{
. 任意字符
\d 任意数字
[A-Z] 从A到Z的任意字符(大写)
[a-z] 从a到z的任意字符(小写)
[A-Za-z] 从a到z的任意字符(大小写不敏感)
[^/]+ 任意字符直到一个前斜线(不包含斜线本身)
+ 一个或多个前面的字符
? 零个或多个前面的字符
{1,3} 1个到3个之间前面的字符(包括1和3)
}}}

==== 命名变量 ====

传给函数以year命名的变量
{{{
(r'^articles/(?P<year>\d{4})/$', views.year_archive),
}}}

==== 指定参数 ====
传递参数,动态选择模板,有时配合默认参数会很方便
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})
}}}
==== include URL配置 ====
注意:指向inclue()的正则表达式不包含$(字符串结尾匹配符),但包含一个末尾斜线
{{{
(r'^photos/', include('mysite.photos.urls')),
}}}
include时可以附加额外的参数
{{{
#额外选项将一直传递给include的URL配置的每一行,仅当你确认在include的URL配置里每个视图接受你传递的选项时才有意义
(r'^blog/', include('inner'), {'blogid': 3}),
}}}
== 模版 ==
=== 传入参数 ===

{{{
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
=== 调用对象的方法 ===
如对于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
}}}
=== 插入变量 ===
{{{
<p>Sincerely,<br />{{ 变量名 }}</p>
}}}

=== 块语句 ===

==== if ====
{% if %}标签不允许同一标签里同时出现and和or

可以使用嵌套的{% if %}来表示and和or
 
{{{
{%if xxx%}
 <p>内容1</p>
{%else%}
 <p>内容2</p>
{%endif%}
}}}
==== ifequal/ifnotequal ====
{{{
{% ifequal user currentuser %}
<h1>Welcome!</h1>
{% endifequal %}
}}}

参数可以是硬编码的string,数字等,如{% ifequal section 'sitenews' %},{% ifequal section 1.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

==== include ====
{% include 'includes/nav.html' %}

如果给定的模板名不存在,Django将做下面两件事情中的一件:

1,如果DEBUG设置为True,你将看到一个TemplateDoesNotExist异常的错误页面

2,如果DEBUG设置为False,标签将什么也不显示

==== 注释 ====
{# This is a comment #}
模板渲染时注释不会输出,一个注释不能分成多行
 
==== 使用模板文件 ====
{{{
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())
}}}




=== 过滤器 ===

==== date ====
把ship_date变量传递给过滤器,并给date过滤器传递了一个参数“F j, Y”,date过滤器以给定参数的形式格式化日期
{{{
{{ship_date|date:"F j, Y"}}
}}}
==== escape / linebreaks ====
escape转义给定的string里出现的&符,引号,尖括号

常用于处理用户提交的数据和确认合法的XML和XHTML数据

escape文本内容然后把换行转换成p标签
{{{
{{ my_text|escape|linebreaks }}
}}}

显示bio变量的前30个字,过滤器参数一直使用双引号
{{{
{{ bio|truncatewords:"30" }}
}}}

==== addslashed ====
在任何后斜线,单引号,双引号前添加一个后斜线,常用于输出文本到JavaScript字符串

==== length ====
返回值的长度,你可以在一个list或string上做此操作

== 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
Line 200: Line 503:
 方便使用命令行, 用API时可以直接看到结果.

        * len() 数目

 注意:用count()进行统计数目更有效率.

        * list() 列表

          entry_list = list(Entry.objects.all())

   注意:可能耗尽你的内存

== 对象集切片(slice) ==
前5个对象
{{{
Entry.objects.all()[:5]
}}}

对象5-10
{{{
Entry.objects.all()[5:10]
}}}

一般来说,给QuerySet切片会返回一个新的QuerySet,同时不执行query(查询).一个例外是当你用切片的"step"参数的时候.如下,返回前10个元素的编号为偶数的元素
{{{
Entry.objects.all()[:10:2]
}}}

To retrieve a single object rather than a list (e.g. SELECT foo FROM bar LIMIT 1), use a simple index instead of a slice. For example, this returns the first Entry in the database, after ordering entries alphabetically by headline:

Entry.objects.order_by('headline')[0]

This is roughly equivalent to:

Entry.objects.order_by('headline')[0:1].get()

Note, however, that the first of these will raise IndexError while the second will raise DoesNotExist if no objects match the given criteria.
QuerySet methods that return new QuerySets

Django provides a range of QuerySet refinement methods that modify either the types of results returned by the QuerySet or the way its SQL query is executed.
filter(**kwargs)

Returns a new QuerySet containing objects that match the given lookup parameters.

The lookup parameters (**kwargs) should be in the format described in Field lookups below. Multiple parameters are joined via AND in the underlying SQL statement.
exclude(**kwargs)

Returns a new QuerySet containing objects that do not match the given lookup parameters.

The lookup parameters (**kwargs) should be in the format described in Field lookups below. Multiple parameters are joined via AND in the underlying SQL statement, and the whole thing is enclosed in a NOT().

This example excludes all entries whose pub_date is the current date/time AND whose headline is "Hello":

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')

In SQL terms, that evaluates to:

SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

This example excludes all entries whose pub_date is the current date/time OR whose headline is "Hello":

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')

In SQL terms, that evaluates to:

SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'

Note the second example is more restrictive.
order_by(*fields)

By default, results returned by a QuerySet are ordered by the ordering tuple given by the ordering option in the model's Meta. You can override this on a per-QuerySet basis by using the order_by method.

Example:

Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

The result above will be ordered by pub_date descending, then by headline ascending. The negative sign in front of "-pub_date" indicates descending order. Ascending order is implied. To order randomly, use "?", like so:

Entry.objects.order_by('?')

To order by a field in a different table, add the other table's name and a dot, like so:

Entry.objects.order_by('blogs_blog.name', 'headline')

There's no way to specify whether ordering should be case sensitive. With respect to case-sensitivity, Django will order results however your database backend normally orders them.
distinct()

Returns a new QuerySet that uses SELECT DISTINCT in its SQL query. This eliminates duplicate rows from the query results.

By default, a QuerySet will not eliminate duplicate rows. In practice, this is rarely a problem, because simple queries such as Blog.objects.all() don't introduce the possibility of duplicate result rows.

However, if your query spans multiple tables, it's possible to get duplicate results when a QuerySet is evaluated. That's when you'd use distinct().
values(*fields)

Returns a ValuesQuerySet -- a QuerySet that evaluates to a list of dictionaries instead of model-instance objects.

Each of those dictionaries represents an object, with the keys corresponding to the attribute names of model objects.

This example compares the dictionaries of values() with the normal model objects:

# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
[Beatles Blog]

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]

values() takes optional positional arguments, *fields, which specify field names to which the SELECT should be limited. If you specify the fields, each dictionary will contain only the field keys/values for the fields you specify. If you don't specify the fields, each dictionary will contain a key and value for every field in the database table.

Example:

>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]

A ValuesQuerySet is useful when you know you're only going to need values from a small number of the available fields and you won't need the functionality of a model instance object. It's more efficient to select only the fields you need to use.

Finally, note a ValuesQuerySet is a subclass of QuerySet, so it has all methods of QuerySet. You can call filter() on it, or order_by(), or whatever. Yes, that means these two calls are identical:

Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()

The people who made Django prefer to put all the SQL-affecting methods first, followed (optionally) by any output-affecting methods (such as values()), but it doesn't really matter. This is your chance to really flaunt your individualism.
dates(field, kind, order='ASC')

Returns a DateQuerySet -- a QuerySet that evaluates to a list of datetime.datetime objects representing all available dates of a particular kind within the contents of the QuerySet.

field should be the name of a DateField or DateTimeField of your model.

kind should be either "year", "month" or "day". Each datetime.datetime object in the result list is "truncated" to the given type.

        * "year" returns a list of all distinct year values for the field.
        * "month" returns a list of all distinct year/month values for the field.
        * "day" returns a list of all distinct year/month/day values for the field.

order, which defaults to 'ASC', should be either 'ASC' or 'DESC'. This specifies how to order the results.

Examples:

>>> Entry.objects.dates('pub_date', 'year')
[datetime.datetime(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.datetime(2005, 2, 1), datetime.datetime(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.datetime(2005, 2, 20), datetime.datetime(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.datetime(2005, 3, 20), datetime.datetime(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.datetime(2005, 3, 20)]

select_related()

Returns a QuerySet that will automatically "follow" foreign-key relationships, selecting that additional related-object data when it executes its query. This is a performance booster which results in (sometimes much) larger queries but means later use of foreign-key relationships won't require database queries.

The following examples illustrate the difference between plain lookups and select_related() lookups. Here's standard lookup:

# Hits the database.
e = Entry.objects.get(id=5)

# Hits the database again to get the related Blog object.
b = e.blog

And here's select_related lookup:

# Hits the database.
e = Entry.objects.select_related().get(id=5)

# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog

select_related() follows foreign keys as far as possible. If you have the following models:

class City(models.Model):
    # ...

class Person(models.Model):
    # ...
    hometown = models.ForeignKey(City)

class Book(models.Model):
    # ...
    author = models.ForeignKey(Person)

...then a call to Book.objects.select_related().get(id=4) will cache the related Person and the related City:

b = Book.objects.select_related().get(id=4)
p = b.author # Doesn't hit the database.
c = p.hometown # Doesn't hit the database.

sv = Book.objects.get(id=4) # No select_related() in this example.
p = b.author # Hits the database.
c = p.hometown # Hits the database.

Note that select_related() does not follow foreign keys that have null=True.
extra(select=None, where=None, params=None, tables=None)

Sometimes, the Django query syntax by itself can't easily express a complex WHERE clause. For these edge cases, Django provides the extra() QuerySet modifier -- a hook for injecting specific clauses into the SQL generated by a QuerySet.

By definition, these extra lookups may not be portable to different database engines (because you're explicitly writing SQL code) and violate the DRY principle, so you should avoid them if possible.

Specify one or more of params, select, where or tables. None of the arguments is required, but you should use at least one of them.

select

    The select argument lets you put extra fields in the SELECT clause. It should be a dictionary mapping attribute names to SQL clauses to use to calculate that attribute.

    Example:

    Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})

    As a result, each Entry object will have an extra attribute, is_recent, a boolean representing whether the entry's pub_date is greater than Jan. 1, 2006.

    Django inserts the given SQL snippet directly into the SELECT statement, so the resulting SQL of the above example would be:

    SELECT blog_entry.*, (pub_date > '2006-01-01')
    FROM blog_entry;

    The next example is more advanced; it does a subquery to give each resulting Blog object an entry_count attribute, an integer count of associated Entry objects:

    Blog.objects.extra(
        select={
            'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
        },
    )

    (In this particular case, we're exploiting the fact that the query will already contain the blog_blog table in its FROM clause.)

    The resulting SQL of the above example would be:

    SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id)
    FROM blog_blog;

    Note that the parenthesis required by most database engines around subqueries are not required in Django's select clauses. Also note that some database backends, such as some MySQL versions, don't support subqueries.
where / tables

    You can define explicit SQL WHERE clauses -- perhaps to perform non-explicit joins -- by using where. You can manually add tables to the SQL FROM clause by using tables.

    where and tables both take a list of strings. All where parameters are "AND"ed to any other search criteria.

    Example:

    Entry.objects.extra(where=['id IN (3, 4, 5, 20)'])

    ...translates (roughly) into the following SQL:

    SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20);

params

    The select and where parameters described above may use standard Python database string placeholders -- '%s' to indicate parameters the database engine should automatically quote. The params argument is a list of any extra parameters to be substituted.

    Example:

    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])

    Always use params instead of embedding values directly into select or where because params will ensure values are quoted correctly according to your particular backend. (For example, quotes will be escaped correctly.)

    Bad:

    Entry.objects.extra(where=["headline='Lennon'"])

    Good:

    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])

QuerySet methods that do not return QuerySets

The following QuerySet methods evaluate the QuerySet and return something other than a QuerySet.

These methods do not use a cache (see Caching and QuerySets below). Rather, they query the database each time they're called.
get(**kwargs)

Returns the object matching the given lookup parameters, which should be in the format described in Field lookups.

get() raises AssertionError if more than one object was found.

get() raises a DoesNotExist exception if an object wasn't found for the given parameters. The DoesNotExist exception is an attribute of the model class. Example:

Entry.objects.get(id='foo') # raises Entry.DoesNotExist

The DoesNotExist exception inherits from django.core.exceptions.ObjectDoesNotExist, so you can target multiple DoesNotExist exceptions. Example:

from django.core.exceptions import ObjectDoesNotExist
try:
    e = Entry.objects.get(id=3)
    b = Blog.objects.get(id=1)
except ObjectDoesNotExist:
    print "Either the entry or blog doesn't exist."

create(**kwargs)

A convenience method for creating an object and saving it all in one step. Thus:

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")

and:

p = Person(first_name="Bruce", last_name="Springsteen")
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/')
Line 505: Line 521:

are equivalent.
get_or_create(**kwargs)

A convenience method for looking up an object with the given kwargs, creating one if necessary.

Returns a tuple of (object, created), where object is the retrieved or created object and created is a boolean specifying whether a new object was created.

This is meant as a shortcut to boilerplatish code and is mostly useful for data-import scripts. For example:

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()

This pattern gets quite unwieldy as the number of fields in a model goes up. The above example can be rewritten using get_or_create() like so:

obj, created = Person.objects.get_or_create(first_name='John', last_name='Lennon',
                  defaults={'birthday': date(1940, 10, 9)})

Any keyword arguments passed to get_or_create() -- except an optional one called defaults -- will be used in a get() call. If an object is found, get_or_create() returns a tuple of that object and False. If an object is not found, get_or_create() will instantiate and save a new object, returning a tuple of the new object and True. The new object will be created according to this algorithm:

defaults = kwargs.pop('defaults', {})
params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
params.update(defaults)
obj = self.model(**params)
obj.save()

In English, that means start with any non-'defaults' keyword argument that doesn't contain a double underscore (which would indicate a non-exact lookup). Then add the contents of defaults, overriding any keys if necessary, and use the result as the keyword arguments to the model class.

If you have a field named defaults and want to use it as an exact lookup in get_or_create(), just use 'defaults__exact', like so:

Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})

Finally, a word on using get_or_create() in Django views. As mentioned earlier, get_or_create() is mostly useful in scripts that need to parse data and create new records if existing ones aren't available. But if you need to use get_or_create() in a view, please make sure to use it only in POST requests unless you have a good reason not to. GET requests shouldn't have any effect on data; use POST whenever a request to a page has a side effect on your data. For more, see Safe methods in the HTTP spec.
count()

Returns an integer representing the number of objects in the database matching the QuerySet. count() never raises exceptions.

Example:

# Returns the total number of entries in the database.
Entry.objects.count()

# Returns the number of entries whose headline contains 'Lennon'
Entry.objects.filter(headline__contains='Lennon').count()

count() performs a SELECT COUNT(*) behind the scenes, so you should always use count() rather than loading all of the record into Python objects and calling len() on the result.

Depending on which database you're using (e.g. PostgreSQL vs. MySQL), count() may return a long integer instead of a normal Python integer. This is an underlying implementation quirk that shouldn't pose any real-world problems.
in_bulk(id_list)

Takes a list of primary-key values and returns a dictionary mapping each primary-key value to an instance of the object with the given ID.

Example:

>>> Blog.objects.in_bulk([1])
{1: Beatles Blog}
>>> Blog.objects.in_bulk([1, 2])
{1: Beatles Blog, 2: Cheddar Talk}
>>> Blog.objects.in_bulk([])
{}

If you pass in_bulk() an empty list, you'll get an empty dictionary.
latest(field_name=None)

Returns the latest object in the table, by date, using the field_name provided as the date field.

This example returns the latest Entry in the table, according to the pub_date field:

Entry.objects.latest('pub_date')

If your model's Meta specifies get_latest_by, you can leave off the field_name argument to latest(). Django will use the field specified in get_latest_by by default.

Like get(), latest() raises DoesNotExist if an object doesn't exist with the given parameters.

Note latest() exists purely for convenience and readability.
Field lookups

Field lookups are how you specify the meat of an SQL WHERE clause. They're specified as keyword arguments to the QuerySet methods filter(), exclude() and get().

Basic lookups keyword arguments take the form field__lookuptype=value. (That's a double-underscore). For example:

Entry.objects.filter(pub_date__lte='2006-01-01')

translates (roughly) into the following SQL:

SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

How this is possible

Python has the ability to define functions that accept arbitrary name-value arguments whose names and values are evaluated at runtime. For more information, see Keyword Arguments in the official Python tutorial.

If you pass an invalid keyword argument, a lookup function will raise TypeError.

The database API supports the following lookup types:
exact

Exact match. If the value provided for comparison is None, it will be interpreted as an SQL NULL (See isnull for more details).

Examples:

Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)

SQL equivalents:

SELECT ... WHERE id = 14;
SELECT ... WHERE id = NULL;

iexact

Case-insensitive exact match.

Example:

Blog.objects.get(name__iexact='beatles blog')

SQL equivalent:

SELECT ... WHERE name ILIKE 'beatles blog';

Note this will match 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG', etc.
contains

Case-sensitive containment test.

Example:

Entry.objects.get(headline__contains='Lennon')

SQL equivalent:

SELECT ... WHERE headline LIKE '%Lennon%';

Note this will match the headline 'Today Lennon honored' but not 'today lennon honored'.

SQLite doesn't support case-sensitive LIKE statements; contains acts like icontains for SQLite.
icontains

Case-insensitive containment test.

Example:

Entry.objects.get(headline__icontains='Lennon')

SQL equivalent:

SELECT ... WHERE headline ILIKE '%Lennon%';

gt

Greater than.

Example:

Entry.objects.filter(id__gt=4)

SQL equivalent:

SELECT ... WHERE id > 4;

gte

Greater than or equal to.
lt

Less than.
lte

Less than or equal to.
in

In a given list.

Example:

Entry.objects.filter(id__in=[1, 3, 4])

SQL equivalent:

SELECT ... WHERE id IN (1, 3, 4);

startswith

Case-sensitive starts-with.

Example:

Entry.objects.filter(headline__startswith='Will')

SQL equivalent:

SELECT ... WHERE headline LIKE 'Will%';

SQLite doesn't support case-sensitive LIKE statements; startswith acts like istartswith for SQLite.
istartswith

Case-insensitive starts-with.

Example:

Entry.objects.filter(headline__istartswith='will')

SQL equivalent:

SELECT ... WHERE headline ILIKE 'Will%';

endswith

Case-sensitive ends-with.

Example:

Entry.objects.filter(headline__endswith='cats')

SQL equivalent:

SELECT ... WHERE headline LIKE '%cats';

SQLite doesn't support case-sensitive LIKE statements; endswith acts like iendswith for SQLite.
iendswith

Case-insensitive ends-with.

Example:

Entry.objects.filter(headline__iendswith='will')

SQL equivalent:

SELECT ... WHERE headline ILIKE '%will'

range

Range test (inclusive).

Example:

start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

SQL equivalent:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

You can use range anywhere you can use BETWEEN in SQL -- for dates, numbers and even characters.
year

For date/datetime fields, exact year match. Takes a four-digit year.

Example:

Entry.objects.filter(pub_date__year=2005)

SQL equivalent:

SELECT ... WHERE EXTRACT('year' FROM pub_date) = '2005';

(The exact SQL syntax varies for each database engine.)
month

For date/datetime fields, exact month match. Takes an integer 1 (January) through 12 (December).

Example:

Entry.objects.filter(pub_date__month=12)

SQL equivalent:

SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';

(The exact SQL syntax varies for each database engine.)
day

For date/datetime fields, exact day match.

Example:

Entry.objects.filter(pub_date__day=3)

SQL equivalent:

SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';

(The exact SQL syntax varies for each database engine.)

Note this will match any record with a pub_date on the third day of the month, such as January 3, July 3, etc.
isnull

Takes either True or False, which correspond to SQL queries of IS NULL and IS NOT NULL, respectively.

Example:

Entry.objects.filter(pub_date__isnull=True)

SQL equivalent:

SELECT ... WHERE pub_date IS NULL;

__isnull=True vs __exact=None

There is an important difference between __isnull=True and __exact=None. __exact=None will always return an empty result set, because SQL requires that no value is equal to NULL. __isnull determines if the field is currently holding the value of NULL without performing a comparison.
search

A boolean full-text search, taking advantage of full-text indexing. This is like contains but is significantly faster due to full-text indexing.

Note this is only available in MySQL and requires direct manipulation of the database to add the full-text index.
Default lookups are exact

If you don't provide a lookup type -- that is, if your keyword argument doesn't contain a double underscore -- the lookup type is assumed to be exact.

For example, the following two statements are equivalent:

Blog.objects.get(id__exact=14) # Explicit form
Blog.objects.get(id=14) # __exact is implied

This is for convenience, because exact lookups are the common case.
The pk lookup shortcut

For convenience, Django provides a pk lookup type, which stands for "primary_key".

In the example Blog model, the primary key is the id field, so these three statements are equivalent:

Blog.objects.get(id__exact=14) # Explicit form
Blog.objects.get(id=14) # __exact is implied
Blog.objects.get(pk=14) # pk implies id__exact

The use of pk isn't limited to __exact queries -- any query term can be combined with pk to perform a query on the primary key of a model:

# Get blogs entries with id 1, 4 and 7
Blog.objects.filter(pk__in=[1,4,7])
# Get all blog entries with id > 14
Blog.objects.filter(pk__gt=14)

pk lookups also work across joins. For example, these three statements are equivalent:

Entry.objects.filter(blog__id__exact=3) # Explicit form
Entry.objects.filter(blog__id=3) # __exact is implied
Entry.objects.filter(blog__pk=3) # __pk implies __id__exact

Lookups that span relationships

Django offers a powerful and intuitive way to "follow" relationships in lookups, taking care of the SQL JOINs for you automatically, behind the scenes. To span a relationship, just use the field name of related fields across models, separated by double underscores, until you get to the field you want.

This example retrieves all Entry objects with a Blog whose name is 'Beatles Blog':

Entry.objects.filter(blog__name__exact='Beatles Blog')

This spanning can be as deep as you'd like.

It works backwards, too. To refer to a "reverse" relationship, just use the lowercase name of the model.

This example retrieves all Blog objects which have at least one Entry whose headline contains 'Lennon':

Blog.objects.filter(entry__headline__contains='Lennon')

Escaping parenthesis and underscores in LIKE statements

The field lookups that equate to LIKE SQL statements (iexact, contains, icontains, startswith, istartswith, endswith and iendswith) will automatically escape the two special characters used in LIKE statements -- the percent sign and the underscore. (In a LIKE statement, the percent sign signifies a multiple-character wildcard and the underscore signifies a single-character wildcard.)

This means things should work intuitively, so the abstraction doesn't leak. For example, to retrieve all the entries that contain a percent sign, just use the percent sign as any other character:

Entry.objects.filter(headline__contains='%')

Django takes care of the quoting for you; the resulting SQL will look something like this:

SELECT ... WHERE headline LIKE '%\%%';

Same goes for underscores. Both percentage signs and underscores are handled for you transparently.
Caching and QuerySets

Each QuerySet contains a cache, to minimize database access. It's important to understand how it works, in order to write the most efficient code.

In a newly created QuerySet, the cache is empty. The first time a QuerySet is evaluated -- and, hence, a database query happens -- Django saves the query results in the QuerySet's cache and returns the results that have been explicitly requested (e.g., the next element, if the QuerySet is being iterated over). Subsequent evaluations of the QuerySet reuse the cached results.

Keep this caching behavior in mind, because it may bite you if you don't use your QuerySets correctly. For example, the following will create two QuerySets, evaluate them, and throw them away:

print [e.headline for e in Entry.objects.all()]
print [e.pub_date for e in Entry.objects.all()]

That means the same database query will be executed twice, effectively doubling your database load. Also, there's a possibility the two lists may not include the same database records, because an Entry may have been added or deleted in the split second between the two requests.

To avoid this problem, simply save the QuerySet and reuse it:

queryset = Poll.objects.all()
print [p.headline for p in queryset] # Evaluate the query set.
print [p.pub_date for p in queryset] # Re-use the cache from the evaluation.

Comparing objects

To compare two model instances, just use the standard Python comparison operator, the double equals sign: ==. Behind the scenes, that compares the primary key values of two models.

Using the Entry example above, the following two statements are equivalent:

some_entry == other_entry
some_entry.id == other_entry.id

If a model's primary key isn't called id, no problem. Comparisons will always use the primary key, whatever it's called. For example, if a model's primary key field is called name, these two statements are equivalent:

some_obj == other_obj
some_obj.name == other_obj.name

Complex lookups with Q objects

Keyword argument queries -- in filter(), etc. -- are "AND"ed together. If you need to execute more complex queries (for example, queries with OR statements), you can use Q objects.

A Q object (django.db.models.Q) is an object used to encapsulate a collection of keyword arguments. These keyword arguments are specified as in "Field lookups" above.

For example, this Q object encapsulates a single LIKE query:

Q(question__startswith='What')

Q objects can be combined using the & and | operators. When an operator is used on two Q objects, it yields a new Q object.

For example, this statement yields a single Q object that represents the "OR" of two "question__startswith" queries:

Q(question__startswith='Who') | Q(question__startswith='What')

This is equivalent to the following SQL WHERE clause:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

You can compose statements of arbitrary complexity by combining Q objects with the & and | operators. You can also use parenthetical grouping.

Each lookup function that takes keyword-arguments (e.g. filter(), exclude(), get()) can also be passed one or more Q objects as positional (not-named) arguments. If you provide multiple Q object arguments to a lookup function, the arguments will be "AND"ed together. For example:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

... roughly translates into the SQL:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

Lookup functions can mix the use of Q objects and keyword arguments. All arguments provided to a lookup function (be they keyword arguments or Q objects) are "AND"ed together. However, if a Q object is provided, it must precede the definition of any keyword arguments. For example:

Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who')

... would be a valid query, equivalent to the previous example; but:

# INVALID QUERY
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

... would not be valid.

See the OR lookups examples page for more examples.
Related objects

When you define a relationship in a model (i.e., a ForeignKey, OneToOneField, or ManyToManyField), instances of that model will have a convenient API to access the related object(s).

Using the models at the top of this page, for example, an Entry object e can get its associated Blog object by accessing the blog attribute: e.blog.

(Behind the scenes, this functionality is implemented by Python descriptors. This shouldn't really matter to you, but we point it out here for the curious.)

Django also creates API accessors for the "other" side of the relationship -- the link from the related model to the model that defines the relationship. For example, a Blog object b has access to a list of all related Entry objects via the entry_set attribute: b.entry_set.all().

All examples in this section use the sample Blog, Author and Entry models defined at the top of this page.
One-to-many relationships
Forward

If a model has a ForeignKey, instances of that model will have access to the related (foreign) object via a simple attribute of the model.

Example:

e = Entry.objects.get(id=2)
e.blog # Returns the related Blog object.

You can get and set via a foreign-key attribute. As you may expect, changes to the foreign key aren't saved to the database until you call save(). Example:

e = Entry.objects.get(id=2)
e.blog = some_blog
e.save()

If a ForeignKey field has null=True set (i.e., it allows NULL values), you can assign None to it. Example:

e = Entry.objects.get(id=2)
e.blog = None
e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"

Forward access to one-to-many relationships is cached the first time the related object is accessed. Subsequent accesses to the foreign key on the same object instance are cached. Example:

e = Entry.objects.get(id=2)
print e.blog # Hits the database to retrieve the associated Blog.
print e.blog # Doesn't hit the database; uses cached version.

Note that the select_related() QuerySet method recursively prepopulates the cache of all one-to-many relationships ahead of time. Example:

e = Entry.objects.select_related().get(id=2)
print e.blog # Doesn't hit the database; uses cached version.
print e.blog # Doesn't hit the database; uses cached version.

select_related() is documented in the "QuerySet methods that return new QuerySets" section above.
Backward

If a model has a ForeignKey, instances of the foreign-key model will have access to a Manager that returns all instances of the first model. By default, this Manager is named FOO_set, where FOO is the source model name, lowercased. This Manager returns QuerySets, which can be filtered and manipulated as described in the "Retrieving objects" section above.

Example:

b = Blog.objects.get(id=1)
b.entry_set.all() # Returns all Entry objects related to Blog.

# b.entry_set is a Manager that returns QuerySets.
b.entry_set.filter(headline__contains='Lennon')
b.entry_set.count()

You can override the FOO_set name by setting the related_name parameter in the ForeignKey() definition. For example, if the Entry model was altered to blog = ForeignKey(Blog, related_name='entries'), the above example code would look like this:

b = Blog.objects.get(id=1)
b.entries.all() # Returns all Entry objects related to Blog.

# b.entries is a Manager that returns QuerySets.
b.entries.filter(headline__contains='Lennon')
b.entries.count()

You cannot access a reverse ForeignKey Manager from the class; it must be accessed from an instance. Example:

Blog.entry_set # Raises AttributeError: "Manager must be accessed via instance".

In addition to the QuerySet methods defined in "Retrieving objects" above, the ForeignKey Manager has these additional methods:

        *

          add(obj1, obj2, ...): Adds the specified model objects to the related object set.

          Example:

          b = Blog.objects.get(id=1)
          e = Entry.objects.get(id=234)
          b.entry_set.add(e) # Associates Entry e with Blog b.

        *

          create(**kwargs): Creates a new object, saves it and puts it in the related object set. Returns the newly created object.

          Example:

          b = Blog.objects.get(id=1)
          e = b.entry_set.create(headline='Hello', body_text='Hi', pub_date=datetime.date(2005, 1, 1))
          # No need to call e.save() at this point -- it's already been saved.

          This is equivalent to (but much simpler than):

          b = Blog.objects.get(id=1)
          e = Entry(blog=b, headline='Hello', body_text='Hi', pub_date=datetime.date(2005, 1, 1))
          e.save()

          Note that there's no need to specify the keyword argument of the model that defines the relationship. In the above example, we don't pass the parameter blog to create(). Django figures out that the new Entry object's blog field should be set to b.
        *

          remove(obj1, obj2, ...): Removes the specified model objects from the related object set.

          Example:

          b = Blog.objects.get(id=1)
          e = Entry.objects.get(id=234)
          b.entry_set.remove(e) # Disassociates Entry e from Blog b.

          In order to prevent database inconsistency, this method only exists on ForeignKey objects where null=True. If the related field can't be set to None (NULL), then an object can't be removed from a relation without being added to another. In the above example, removing e from b.entry_set() is equivalent to doing e.blog = None, and because the blog ForeignKey doesn't have null=True, this is invalid.
        *

          clear(): Removes all objects from the related object set.

          Example:

          b = Blog.objects.get(id=1)
          b.entry_set.clear()

          Note this doesn't delete the related objects -- it just disassociates them.

          Just like remove(), clear() is only available on ForeignKey``s where ``null=True.

To assign the members of a related set in one fell swoop, just assign to it from any iterable object. Example:

b = Blog.objects.get(id=1)
b.entry_set = [e1, e2]

If the clear() method is available, any pre-existing objects will be removed from the entry_set before all objects in the iterable (in this case, a list) are added to the set. If the clear() method is not available, all objects in the iterable will be added without removing any existing elements.

Each "reverse" operation described in this section has an immediate effect on the database. Every addition, creation and deletion is immediately and automatically saved to the database.
Many-to-many relationships

Both ends of a many-to-many relationship get automatic API access to the other end. The API works just as a "backward" one-to-many relationship. See Backward above.

The only difference is in the attribute naming: The model that defines the ManyToManyField uses the attribute name of that field itself, whereas the "reverse" model uses the lowercased model name of the original model, plus '_set' (just like reverse one-to-many relationships).

An example makes this easier to understand:

e = Entry.objects.get(id=3)
e.authors.all() # Returns all Author objects for this Entry.
e.authors.count()
e.authors.filter(name__contains='John')

a = Author.objects.get(id=5)
a.entry_set.all() # Returns all Entry objects for this Author.

Like ForeignKey, ManyToManyField can specify related_name. In the above example, if the ManyToManyField in Entry had specified related_name='entries', then each Author instance would have an entries attribute instead of entry_set.
One-to-one relationships

The semantics of one-to-one relationships will be changing soon, so we don't recommend you use them.
How are the backward relationships possible?

Other object-relational mappers require you to define relationships on both sides. The Django developers believe this is a violation of the DRY (Don't Repeat Yourself) principle, so Django only requires you to define the relationship on one end.

But how is this possible, given that a model class doesn't know which other model classes are related to it until those other model classes are loaded?

The answer lies in the INSTALLED_APPS setting. The first time any model is loaded, Django iterates over every model in INSTALLED_APPS and creates the backward relationships in memory as needed. Essentially, one of the functions of INSTALLED_APPS is to tell Django the entire model domain.
Queries over related objects

Queries involving related objects follow the same rules as queries involving normal value fields. When specifying the the value for a query to match, you may use either an object instance itself, or the primary key value for the object.

For example, if you have a Blog object b with id=5, the following three queries would be identical:

Entry.objects.filter(blog=b) # Query using object instance
Entry.objects.filter(blog=b.id) # Query using id from instance
Entry.objects.filter(blog=5) # Query using id directly

Deleting objects

The delete method, conveniently, is named delete(). This method immediately deletes the object and has no return value. Example:

e.delete()

You can also delete objects in bulk. Every QuerySet has a delete() method, which deletes all members of that QuerySet.

For example, this deletes all Entry objects with a pub_date year of 2005:

Entry.objects.filter(pub_date__year=2005).delete()

Note that delete() is the only QuerySet method that is not exposed on a Manager itself. This is a safety mechanism to prevent you from accidentally requesting Entry.objects.delete(), and deleting all the entries. If you do want to delete all the objects, then you have to explicitly request a complete query set:

Entry.objects.all().delete()

Extra instance methods

In addition to save(), delete(), a model object might get any or all of the following methods:
get_FOO_display()

For every field that has choices set, the object will have a get_FOO_display() method, where FOO is the name of the field. This method returns the "human-readable" value of the field. For example, in the following model:

GENDER_CHOICES = (
    ('M', 'Male'),
    ('F', 'Female'),
)
class Person(models.Model):
    name = models.CharField(maxlength=20)
    gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)

...each Person instance will have a get_gender_display() method. Example:

>>> p = Person(name='John', gender='M')
>>> p.save()
>>> p.gender
'M'
>>> p.get_gender_display()
'Male'

get_next_by_FOO(**kwargs) and get_previous_by_FOO(**kwargs)

For every DateField and DateTimeField that does not have null=True, the object will have get_next_by_FOO() and get_previous_by_FOO() methods, where FOO is the name of the field. This returns the next and previous object with respect to the date field, raising the appropriate DoesNotExist exception when appropriate.

Both methods accept optional keyword arguments, which should be in the format described in Field lookups above.

Note that in the case of identical date values, these methods will use the ID as a fallback check. This guarantees that no records are skipped or duplicated. For a full example, see the lookup API sample model.
get_FOO_filename()

For every FileField, the object will have a get_FOO_filename() method, where FOO is the name of the field. This returns the full filesystem path to the file, according to your MEDIA_ROOT setting.

Note that ImageField is technically a subclass of FileField, so every model with an ImageField will also get this method.
get_FOO_url()

For every FileField, the object will have a get_FOO_url() method, where FOO is the name of the field. This returns the full URL to the file, according to your MEDIA_URL setting. If the value is blank, this method returns an empty string.
get_FOO_size()

For every FileField, the object will have a get_FOO_size() method, where FOO is the name of the field. This returns the size of the file, in bytes. (Behind the scenes, it uses os.path.getsize.)
save_FOO_file(filename, raw_contents)

For every FileField, the object will have a save_FOO_file() method, where FOO is the name of the field. This saves the given file to the filesystem, using the given filename. If a file with the given filename already exists, Django adds an underscore to the end of the filename (but before the extension) until the filename is available.
get_FOO_height() and get_FOO_width()

For every ImageField, the object will have get_FOO_height() and get_FOO_width() methods, where FOO is the name of the field. This returns the height (or width) of the image, as an integer, in pixels.
Falling back to raw SQL

If you find yourself needing to write an SQL query that is too complex for Django's database-mapper to handle, you can fall back into raw-SQL statement mode.

The preferred way to do this is by giving your model custom methods or custom manager methods that execute queries. Although there's nothing in Django that requires database queries to live in the model layer, this approach keeps all your data-access logic in one place, which is smart from an code-organization standpoint. For instructions, see Executing custom SQL.

Finally, it's important to note that the Django database layer is merely an interface to your database. You can access your database via other tools, programming languages or database frameworks; there's nothing Django-specific about your database.
publisher_list = Publisher.objects.all()
}}}

Django绝对简明手册(写作中) TableOfContents

张沈鹏     电子科技大学  生物医学工程/计算机科学与技术
你看到的此文档,可能不是最新的,
欢迎访问我的 Blog 了解最新的变化.
也欢迎加入我的Google讨论群,
讨论一切关于
C++,STL,Boost,
XML,CSS,Javascript,XUL
Python,Django
的问题

[http://groups.google.com/group/go2program 我的Google讨论群] [http://zsp.javaeye.com 我的Blog]

更新:2007.6 beta

  • Django版本:9.6
  • Python版本:2.5

1. 序言

现在学的东西很容易忘记,写这篇文章的目的是能让我在需要时快速找回当时的感觉. Find Fun !

许多细节在<<Django Step by Step>>中有介绍,我不重复.

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.0.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.0.2. 常用正则式

.    任意字符  
\d        任意数字  
[A-Z]     从A到Z的任意字符(大写)  
[a-z]     从a到z的任意字符(小写)  
[A-Za-z]  从a到z的任意字符(大小写不敏感)  
[^/]+     任意字符直到一个前斜线(不包含斜线本身)  
+         一个或多个前面的字符  
?         零个或多个前面的字符  
{1,3}     1个到3个之间前面的字符(包括1和3)  

4.0.3. 命名变量

传给函数以year命名的变量

(r'^articles/(?P<year>\d{4})/$', views.year_archive), 

4.0.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.0.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()

DjangoZipManual (last edited 2009-12-25 07:10:12 by localhost)