在使用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
例如:
>>> e = Entry.objects.get(id=2) >>> e.blog # 通过这种方式,就能获取到外键blog对象
如果你想改变关联的外键,也很简单,如:
>>> 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.
如:
>>> 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()等。
如:
>>> 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'),那么代码就成了这样:
>>> b = Blog.objects.get(id=1) >>> b.entries.all() # 返回所有和当前Blog有关联的Entry的集合
另外,对于上面提到的QuerySet还有如下一些方法,可供使用,如add()、create()、remove()、clear()等。
2、Many-to-many 关系
和外键约束类似,处理many-to-many关系,在后台处理上是去维护两个一对多的关联关系,这两个一对多的关系在访问上不同的是:定义了多对多关系属性的模型对象,通过属性直接访问,被关联的模型在访问时,就要使用:小写的模型名称_set的方式进行访问(这里和外键是一样的访问方式);如下:
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关系
如下:
class EntryDetail(models.Model): entry = models.OneToOneField(Entry) details = models.TextField() ed = EntryDetail.objects.get(id=2) ed.entry # Returns the related Entry object.
在访问‘反转’模型的方式上唯一不同的是:一对一返回的是一个实例对象,而非结果集,所以,对应的'反转'模型就有一个模型名称对应的属性(全小写),如下:
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、关联关系上的查询
涉及到相关关系查询时,其查询规则和普通查询类似,当指定查询条件时。可以是主键值或者实例对象;如:
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