【Django】什么时候使用select_related()或prefetch_related()

来源:互联网 发布:聚合数据 股票接口 编辑:程序博客网 时间:2024/06/05 20:11

Django获取数据实体的时候,返回的对象一个实体或多个实体,也就是QuerySet,它是Django专有的东西,具体的理解,它是类似Python的字典的东西,但它并不实现字典的所有方法。今天讲解的是它其中的一个函数select_related()。

select_related()使用的场景,是获取实体的同时,能快速获取到它对应的外键关系实体。 如果获取实体时没有使用select_related(),要引用该实体的外键关系,那么就会重新连接数据库去获取对应实体了。比如 作者Author 博客Blog 两个表,他们的关系 是一个作者Author有多个博客blog,;当我们想获取到一个作者的同时 直接引用该作者的所有博客时,常规做法是会进行两次数据库连接的,但使用了select_related()后,情况就有所变化了,它第一次连接数据库获取该作者的时候,该作者的所有博客被获取到了。
比如:
author=Author.objects.select_related().get(pk=1) #获取id是1的作者; 获取该博客的同时已经获取到该作者的所有博客
blogs=author.blog #获取id是1作者的所有博客blogs ,这时并不需要连接数据库获取那些博客了。

不使用select_related()时:
author=Author.objects.get(pk=1) #获取id是1的作者;仅仅获取该作者的实体
blogs=author.blog #获取id是1作者的所有博客blogs ,但需要连接数据库获取该作者的那些博客。

select_related()提供了一个备选参数depth,执行获取对象关联实体的深度。如 select_related(depth=2),这时不仅仅获取到相关的博客,还能获取到博客的关联实体,比如博客的类别(另一个和blog表相对应的表)之类的。如果不指定depth,默认情况将会获取到该作者的所有关联对象的 包括关联对象的子关联对象。由此可以想象,使用它有利有弊,当自己需要对象相关关联对象的时候,可以使用它,只是这样第一次查询的时候,将进行不少表的操作(要看表关联复杂程度)。

所以当我们获取对象需要它相关联的对象时,就请用select_related()吧,如果该对象关联的表很多,请指定depth的值,避免资源的浪费;反之避免select_related()。

prefetch_related ()的使用:

表:

class City(models.Model):
name = models.CharField(max_length=5)
province = models.ForeignKey(Province)
def unicode(self):
return self.name

class Person(models.Model):
firstname = models.CharField(max_length=10)
lastname = models.CharField(max_length=10)
visitation = models.ManyToManyField(City, related_name = “visitor”)
hometown = models.ForeignKey(City, related_name = “birth”)
living = models.ForeignKey(City, related_name = “citizen”)
def unicode(self):
return self.firstname + self.lastname

要获得张三所有去过的城市。首先注意到Persion.visitation的类型是ManyToManyField,在数据库中,Person表有多个人,City表有多个城市。我们要在通过循环打印张三去过的这些城市前,通过张三的“id”限制将相关联的城市预取出来,存到内存中,而不是在打印这些城市的时候再去数据库查找(lazy loading),减少了数据库查询次数。

zhangs= Person.objects.prefetch_related(‘visitation’).get(firstname=u”张”,lastname=u”三”)

for city in zhangs.visitation.all() :
… print city

0 0
原创粉丝点击