Size: 45942
Comment:
|
Size: 42505
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 26: | Line 26: |
Django版本:9.5 Python版本:2.5 |
* Django版本:9.5(准确的说是SVN) * Python版本:2.5 |
Line 30: | Line 30: |
Django Step by Step 作者: limodou | * Django Step by Step 作者: limodou * Django官方手册 |
Line 35: | Line 36: |
本文可以作为复习资料,不宜初学. | |
Line 227: | Line 227: |
== 获取对象 == | == 对象集中读对象 == |
Line 328: | Line 328: |
=== 日期读取 === | == 日期读取 == |
Line 360: | Line 360: |
=== 缓冲外键的查询 === | == 缓冲外键的查询 == |
Line 411: | Line 411: |
=== WHERE语句生成器 === | == WHERE语句生成器 == |
Line 418: | Line 418: |
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. |
(既然避免使用,我就不做介绍了,大家去看官方手册吧) == QuerySet预处理 == 下面的函数会的QuerySet进行预处理,返回相应的类型的数据 这些函数不会使用缓冲,每次调用都会进行数据库查询 === 单个对象直接读 === |
Line 488: | Line 428: |
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: |
返回一个符合给定参数的对象. * 抛出AssertionError如果查询结果大于一个 * 抛出DoesNotExist如果查询结果为空,DoesNotExist异常是model类的一个属性. 比如: {{{ |
Line 495: | Line 435: |
The DoesNotExist exception inherits from django.core.exceptions.ObjectDoesNotExist, so you can target multiple DoesNotExist exceptions. Example: |
}}} DoesNotExist继承了django.core.exceptions.ObjectDoesNotExist,所以你可以用如下的方法来进行操纵 {{{ |
Line 504: | Line 444: |
}}} === 创建保存一步来 === |
|
Line 507: | Line 449: |
A convenience method for creating an object and saving it all in one step. Thus: |
{{{ |
Line 510: | Line 451: |
and: |
}}} 等价于 {{{ |
Line 515: | Line 456: |
are equivalent. |
}}} === 没有我就自动填 === |
Line 519: | Line 461: |
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: |
根据参数查找目标,如果目标不存在则自动来创建 返回一个元组(tuple) {{{ (object, created) }}} object是查询或者创建的对象,created表明是否进行了创建 在那种千篇一律的数据导入脚本中,它可以解放生产力.比如 {{{ |
Line 528: | Line 474: |
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9)) | obj = Person( first_name='John', last_name='Lennon', birthday=date(1940, 10, 9) ) |
Line 530: | Line 480: |
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: |
}}} 等价于 {{{ obj, created = Person.objects.get_or_create( first_name='John', last_name='Lennon', defaults={'birthday': date(1940, 10, 9)} ) }}} 这里,除了defaults外的所有参数都会用来查询,如果找到了返回对象的元组和False. 如果找不到,会新建且保存一个对象,返回新建的对象和True. 新对象的建立流程如下 {{{ |
Line 543: | Line 495: |
}}} 以下两段我看不懂 |
|
Line 550: | Line 505: |
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. | 最后,介绍一下get_or_create()在view中的使用.如上所述,get_or_create()可以在数据不存在时进行创建.但是,如果你需要在view中使用它,除非你有很好的理由,否则强烈建议仅用POST来传送数据.GET原则上不应该修改数据,用POST来干这件事.Safe methods in the HTTP章节对此进行了深入探讨. === 查询结果有几许 === |
Line 553: | Line 510: |
Returns an integer representing the number of objects in the database matching the QuerySet. count() never raises exceptions. Example: |
返回查询结果的数量. count()不会抛出异常. {{{ |
Line 562: | Line 518: |
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. |
}}} count()后台调用SELECT COUNT(*), so you should always use count() rather than loading all of the record into Python objects and calling len() on the result. |
Django绝对简明手册(写作中) TableOfContents
张沈鹏 电子科技大学大三 生物医学工程 你看到的此文档,可能不是最新的, 欢迎访问我的 Blog 了解最新的变化. 也欢迎加入我的Google讨论群, 讨论一切关于 C++,STL,Boost, XML,CSS,Javascript,XUL Python,Django 的问题
[http://groups.google.com/group/go2program 我的Google讨论群] [http://www.cppblog.com/zuroc 我的C++Blog] [http://www.cnweblog.com/zuroc/ 我的文学Blog]
-- Any Question,Please Email To [email protected]
更新:2006.10 beta
- Django版本:9.5(准确的说是SVN)
- Python版本:2.5
参考:
- Django Step by Step 作者: limodou
- Django官方手册
1. 序言
现在学的东西很容易忘记,写这篇文章的目的是能让我在需要时快速找回当时的感觉. Find Fun !
许多细节在<<Django Step by Step>>中有介绍,我不重复.
2. 辅助工具
文本替换专家2.5 : 修改站名,APP模块名时用得到
3. 页面模版
3.1. for
3.1.1. 循环字典
{% for item in media.items %} <{{item.0}}> {{item.1|escape}} </{{item.0}}> {% endfor %}
item.0相当于key,item.1相当于value
4. 数据库
4.1. 数据库字段的类型
- IPAddressField
- URLField
- USStateField
- XMLField
4.2. 定义对象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()
4.3. 自动增长的主键(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的值,但是你要确保它们不会冲突
4.4. 读取对象集
先构造一个集合(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()
4.5. 条件读取对象集
你需要用filter(过滤器)来构造QuerySet
最常用的方式
filter(**kwargs) 包含符合条件的记录
exclude(**kwargs) 排除符合条件的记录
参数 (**kwargs) 格式如下
Entry.objects.filter(pub_date__year=2006)
4.5.1. 多重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())
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
相当于SQL语句
SELECT ... WHERE NOT pub_date > '2005-1-3' AND NOT headline = 'Hello'
4.5.2. 多个参数
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
相当于SQL语句,先AND然后一起NOT
SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
4.5.3. 去除重复项
distinct()
相当于SQL中的" SELECT DISTINCT ",当你进行跨表查询时,同一行可能多次出现,这时你就需要他了
4.6. 对象集中读对象
有如下方式从QuickSet中获得对象(不获取对象时,QuickSet没有真正进行查询)
- iterator 迭代器
for e in Entry.objects.all(): print e.headline
- Slice 切片
- repr() 方便使用命令行, 用API时可以直接看到结果.
- len() 数目 注意:用count()进行统计数目更有效率.
- list() 列表
- entry_list = list(Entry.objects.all()) 注意:可能耗尽你的内存
4.7. 对象集切片(slice)
前5个对象
Entry.objects.all()[:5]
对象5-10
Entry.objects.all()[5:10]
一般来说,给QuerySet切片会返回一个新的QuerySet,同时不执行query(查询).一个例外是当你用切片的"step"参数的时候.如下,返回前10个元素的编号为偶数的元素
Entry.objects.all()[:10:2]
安装'headline'的字母排序后的第一个元素
Entry.objects.order_by('headline')[0]
类似的方法
Entry.objects.order_by('headline')[0:1].get()
注意,如果安装给定的标准第一个不存在,会抛出一个IndexError,第二个不存在会抛出DoesNotExist
4.8. 排序
order_by(*fields)
pub_date安装降序排列,headline安装升序排列
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
随机排列
Entry.objects.order_by('?')
根据另一个表的字段排序,先随入表名然后加上".name
Entry.objects.order_by('blogs_blog.name', 'headline')
暂时还无法区分大小写
4.9. 读取到字典
values(*fields)
返回ValuesQuerySet -- 里面包含的是字典而不是对象.
>>> Blog.objects.filter(name__startswith='Beatles').values() [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]
values()有可选参数,*field,它可以指定SELECT出的字段名.如果你指定了字段名,那么返回的字典中只会包含你给定字段的键值对. 否则,默认会包含表中所有字段的键值对.
>>> Blog.objects.values() [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}], >>> Blog.objects.values('id', 'name') [{'id': 1, 'name': 'Beatles Blog'}]
如果你只需要部分字段的值,用ValuesQuerySet更高效.
最后,注意一个ValuesQuerySet是QuerySet的子集,你仍然可以使用诸如filter(),order_by()来进行操作.也就是说下面的两种方式是等价的.
Blog.objects.values().order_by('id') Blog.objects.order_by('id').values()
Django的作者喜欢先列出所有的SQL相关的方法,然后加上输出相关的函数(比如values()),当然,随个人习惯.
4.10. 日期读取
dates(field, kind, order='ASC')
返回一个DateQuerySet -- datetime对象的list(列表).datetime的值为QuerySet中对象的日期的集合(无重复).
>>> 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)]
field是model的一个DateField或者DateTimeField类型的字段
kind可以是"year","month","day"中的一个.在结果中的每个datetime.datetime对象会根据它进行删减
- "year" 返回 年 的集合
- "month" 返回 年/月 的集合
- "day" 返回 年/月/日 的集合
默认是'ASC'(升序),可指定'DESC'来降序排列
4.11. 缓冲外键的查询
select_related()
返回一个QuerySet,同时会自动对查询其外键指向的对象,如果你要进行一次可能有着大量结果的查询,并且过一会要用到他们的外键,这样做就会加快速度.
# 调用数据库 e = Entry.objects.get(id=5) # 再次调用数据库(blog是他的外键对象) b = e.blog
使用select_related()
# 调用数据库 e = Entry.objects.select_related().get(id=5) # 不必调用数据库(进行了缓冲) b = e.blog
select_related()会递归的查询外键,比如你有以下模型models:
class City(models.Model): # ... class Person(models.Model): # ... hometown = models.ForeignKey(City) class Book(models.Model): # ... author = models.ForeignKey(Person)
如果调用
Book.objects.select_related().get(id=4)
不但缓冲Person,还会缓冲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.
注意:select_related()调用foreign keys不可以为null.
4.12. WHERE语句生成器
extra(select=None, where=None, params=None, tables=None)
有时Django的查询语法不容易够表示复杂的WHERE语法.遇到这种少见的情况,Django提供了extra()来生成可以返回QuerySet的WHERE语句.
需要说明的是,这种查询方式可能有移植数据库的问题,并且违反了"拿来主义(Don't Repeat Youself)"的原则.所以应该尽量避免.
(既然避免使用,我就不做介绍了,大家去看官方手册吧)
4.13. QuerySet预处理
下面的函数会的QuerySet进行预处理,返回相应的类型的数据
这些函数不会使用缓冲,每次调用都会进行数据库查询
4.13.1. 单个对象直接读
get(**kwargs)
返回一个符合给定参数的对象.
抛出AssertionError如果查询结果大于一个
抛出DoesNotExist如果查询结果为空,DoesNotExist异常是model类的一个属性. 比如:
Entry.objects.get(id='foo') # raises Entry.DoesNotExist
DoesNotExist继承了django.core.exceptions.ObjectDoesNotExist,所以你可以用如下的方法来进行操纵
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."
4.13.2. 创建保存一步来
create(**kwargs)
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
等价于
p = Person(first_name="Bruce", last_name="Springsteen") p.save()
4.13.3. 没有我就自动填
get_or_create(**kwargs)
根据参数查找目标,如果目标不存在则自动来创建
返回一个元组(tuple)
(object, created)
object是查询或者创建的对象,created表明是否进行了创建
在那种千篇一律的数据导入脚本中,它可以解放生产力.比如
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()
等价于
obj, created = Person.objects.get_or_create( first_name='John', last_name='Lennon', defaults={'birthday': date(1940, 10, 9)} )
这里,除了defaults外的所有参数都会用来查询,如果找到了返回对象的元组和False. 如果找不到,会新建且保存一个对象,返回新建的对象和True. 新对象的建立流程如下
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 'defaultsexact', like so: Foo.objects.get_or_create(defaults
最后,介绍一下get_or_create()在view中的使用.如上所述,get_or_create()可以在数据不存在时进行创建.但是,如果你需要在view中使用它,除非你有很好的理由,否则强烈建议仅用POST来传送数据.GET原则上不应该修改数据,用POST来干这件事.Safe methods in the HTTP章节对此进行了深入探讨.
4.13.4. 查询结果有几许
count()
返回查询结果的数量. count()不会抛出异常.
# 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()后台调用SELECT COUNT(*), 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 fieldlookuptype=value. (That's a double-underscore). For example: Entry.objects.filter(pub_date
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(idexact=14) Entry.objects.get(idexact=None)
SQL equivalents:
SELECT ... WHERE id = 14; SELECT ... WHERE id = NULL;
iexact
Case-insensitive exact match.
Example:
Blog.objects.get(nameiexact='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
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(headlineicontains='Lennon') SQL equivalent: SELECT ... WHERE headline ILIKE '%Lennon%'; gt Greater than. Example: Entry.objects.filter(id
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(idin=[1, 3, 4]) SQL equivalent: SELECT ... WHERE id IN (1, 3, 4); startswith Case-sensitive starts-with. Example: Entry.objects.filter(headline
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(headlineistartswith='will') SQL equivalent: SELECT ... WHERE headline ILIKE 'Will%'; endswith Case-sensitive ends-with. Example: Entry.objects.filter(headline
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(headlineiendswith='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
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_dateyear=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
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_dateday=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
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(idexact=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(idexact=14) # Explicit form Blog.objects.get(id=14) # exact is implied Blog.objects.get(pk=14) # pk implies idexact The use of pk isn't limited to
# Get blogs entries with id 1, 4 and 7 Blog.objects.filter(pkin=[1,4,7]) # Get all blog entries with id > 14 Blog.objects.filter(pkgt=14)
pk lookups also work across joins. For example, these three statements are equivalent:
Entry.objects.filter(blogidexact=3) # Explicit form Entry.objects.filter(blogid=3) # exact is implied Entry.objects.filter(blogpk=3) # pk implies idexact
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(blognameexact='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(entryheadlinecontains='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(headlinecontains='%') 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
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 "questionstartswith" queries: Q(question 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)),
questionstartswith='Who')
... would be a valid query, equivalent to the previous example; but:
# INVALID QUERY Poll.objects.get(
questionstartswith='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(headlinecontains='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
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.
- 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.
- 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 ForeignKeys where null=True.
- 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.
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(namecontains='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
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.