在使用django时,在模型定义的关系中,如果使用到了ForeignKey, OneToOneField, 或者 ManyToManyField,那么该模型的实例,就有了便捷的API去访问相关的对象。
使用的模型:
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() # On Python 3: def __str__(self): def __unicode__(self): return self.name class Author(models.Model): name = models.CharField(max_length=50) email = models.EmailField() # On Python 3: def __str__(self): def __unicode__(self): return self.name class Entry(models.Model): blog = models.ForeignKey(Blog) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() authors = models.ManyToManyField(Author) n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField() # On Python 3: def __str__(self): def __unicode__(self): return self.headline
1、外键的便捷API
例如:
1
2
|
>>> e
=
Entry.objects.get(
id
=
2
)
>>> e.blog
# 通过这种方式,就能获取到外键blog对象
|
如果你想改变关联的外键,也很简单,如:
1
2
3
|
>>> e
=
Entry.objects.get(
id
=
2
)
>>> e.blog
=
Blog()
>>> e.save()
# 这一步是必须的,只有调用了save后,才会将改变的结果更新到数据库
|
如果在定义外键时,设置null=True,则还可以这么写:e.blog=None
注: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.
如:
1
2
3
|
>>> 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.
|
select_related()方法,获取实例所有相关的模型对象,并缓存起来,在通过外键关系、一对多关系访问对象时,不会再造成数据库访问。
如果一个模型含有外键,该模型的外键的实例对象就有访问Manager管理器的权限,默认情况下,这个管理器的名字是xxx_set, xxx是外键模型名称的小写;这个Manager会返回一个QuerySets,这个QuerySets可以像其他的QuerySet一样,使用各种方法进行操作,如filter()等。
如:
1
2
3
4
5
6
|
>>> b
=
Blog.objects.get(
id
=
1
)
>>> b.entry_set.
all
()
# 返回所有和当前Blog有关联的Entry的集合
# b.entry_set 是一个包含了QuerySet的Manager模型管理器
>>> b.entry_set.
filter
(headline__contains
=
'Lennon'
)
>>> b.entry_set.count()
|
同样的,你也可以设置xxx_set的访问名称,通过在定义外键时,加上related_name,like this :blog=models.Foreign(Blog, related_name='entries'),那么代码就成了这样:
1
2
|
>>> b
=
Blog.objects.get(
id
=
1
)
>>> b.entries.
all
()
# 返回所有和当前Blog有关联的Entry的集合
|
另外,对于上面提到的QuerySet还有如下一些方法,可供使用,如add()、create()、remove()、clear()等。
2、Many-to-many 关系
和外键约束类似,处理many-to-many关系,在后台处理上是去维护两个一对多的关联关系,这两个一对多的关系在访问上不同的是:定义了多对多关系属性的模型对象,通过属性直接访问,被关联的模型在访问时,就要使用:小写的模型名称_set的方式进行访问(这里和外键是一样的访问方式);如下:
1
2
3
4
5
6
7
|
e
=
Entry.objects.get(
id
=
3
)
e.authors.
all
()
# 返回所有Entry关联的素有Author
e.authors.count()
e.authors.
filter
(name__contains
=
'John'
)
a
=
Author.objects.get(
id
=
5
)
a.entry_set.
all
()
# 返回Author所有关联的Entry
|
同样的,many-to-many关联关系同样可以通过related_name来指定访问名称。
3、one-to-one关系
如下:
1
2
3
4
5
|
class
EntryDetail(models.Model):
entry
=
models.OneToOneField(Entry)
details
=
models.TextField()
ed
=
EntryDetail.objects.get(
id
=
2
)
ed.entry
# Returns the related Entry object.
|
在访问‘反转’模型的方式上唯一不同的是:一对一返回的是一个实例对象,而非结果集,所以,对应的'反转'模型就有一个模型名称对应的属性(全小写),如下:
1
2
|
e
=
Entry.objects.get(
id
=
2
)
e.entrydetail
# returns the related EntryDetail object
|
注:If no object has been assigned to this relationship, Django will raise a DoesNotExist exception.
4、关联关系上的查询
涉及到相关关系查询时,其查询规则和普通查询类似,当指定查询条件时。可以是主键值或者实例对象;如:
1
2
3
|
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
|