DRF序列化关于嵌套序列化极其消耗性能问题的解决
DRF序列化给我们提供了一个很方便的序列化与反序列化的方法,但是如果在序列化器中使用嵌套,会极其消耗性能。
class Qctestroombeta(BaseModel):
id = models.CharField(primary_key=True, max_length=36)
name=models.CharField(max_length=64, verbose_name='考场名称')
class Qctestroom(BaseModel):
id = models.CharField(primary_key=True, max_length=36)
name = models.CharField(max_length=64, verbose_name='考场名称')
beta = models.ForeignKey(Qctestroombeta,on_delete=models.CASCADE,null=True,blank=True,verbose_name='模拟考场',related_name='testroom')
上面是两个简单的外键模型
class roomnamebetaSerializers(serializers.ModelSerializer):
name = serializers.CharField(source='beta.name')
class Meta:
model = Qctestroom
fields = ( 'id','name',)
这里的序列化会涉及到外键,我们可以很方便的写出这样的嵌套查询,但是Django在执行查询的时候,会查很多次表,这里的name我们查询的是外键beta的一个字段name。
当第一个用户的数据进行序列化的时候,DRF需要查询一次Qctestroombeta表
第二个用户的数据进行序列化的时候,DRF又需要查询一次Qctestroombeta表
…………
这样的一个序列化器执行一次可能会耗时非常多的时间
django给了我们两个方法来解决这个问题
select_related()
在对QuerySet使用select_related()函数后,Django会获取相应外键对应的对象,从而在之后需要的时候不必再查询数据库了。这种方法我们称为预加载。
tl = Qctestlevel.objects.filter(testroom_id=id,strike=False)
tl = Qctestlevel.objects.select_related().filter(testroom_id=id,strike=False)
这里的select_related里面可以有参数,即你要保存使用的外键类似select_related(beta__name)
select_related() 接受可变长参数,每个参数是需要获取的外键(父表的内容)的字段名,以及外键的外键的字段名、外键的外键的外键…。若要选择外键的外键需要使用两个下划线“__”来连接。
如果有多个要保存的外键,则要使用多个select_related拼接起来
depth
select_related() 接受depth参数,depth参数可以确定select_related的深度。Django会递归遍历指定深度内的所有的OneToOneField和ForeignKey.
tr = Qctestroom.objects.select_related(depth = d).all()
prefetch_related()
多用于多对多和一对多,与select_related不同的是select_related用的是join语句进行查询,如果表太多,则会使join得到的表很长,导致sql语句的性能变低,而prefetch_related是分别查询每张表,然后再分别处理他们之间的关系。
与select_related用法类似。