django开发手册DRF提升Django查询效率,你需要知道的重要操作
Posted 帅气的黑桃J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了django开发手册DRF提升Django查询效率,你需要知道的重要操作相关的知识,希望对你有一定的参考价值。
前言
在Django ORM中,使用prefetch_related
可以避免N+1查询问题,提高查询性能。在实际的开发中,我们通常需要在序列化时嵌套使用prefetch_related
,将嵌套数据一起序列化出来。
快速上手
以下是一个案例,一个项目Project
包含多个Bim模型BimFaceModel
,需要在查询Project
时同时查询其对应的BimFaceModel
信息。
普通的查询代码如下:
class ProjectViewSet(viewsets.ModelViewSet):
queryset = models.Project.objects.all()
serializer_class = ProjectSerializer
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
# 这里是关键,每个查询都会再执行一次查询
for project in queryset:
models.BimFaceModel.objects.filter(project_id=project.project_id)
serializer = self.get_serializer(queryset, many=True)
return ResponseResult(data=serializer.data).to_response()
可以看到,如果不加处理,每次循环都需要再次查询对应的BimFaceModel
信息,会产生N+1查询问题,影响性能。
使用prefetch_related
进行优化:
class ProjectViewSet(viewsets.ModelViewSet):
queryset = models.Project.objects.all()
serializer_class = ProjectSerializer
def list(self, request, *args, **kwargs):
queryset = self.get_queryset().prefetch_related('bimfacemodel_set')
serializer = self.get_serializer(queryset, many=True)
return ResponseResult(data=serializer.data).to_response()
可以看到使用prefetch_related
方法来提前加载Project
对象的bimfacemodel_set
属性。然后在序列化时,可以将每个Project
对象的bimfacemodel_set
一起序列化出来。
但是,在Project
模型中,没有bimfacemodel_set
这个属性,只是对于每个BimFaceModel都有对应的project_id
作为外键。为了嵌套序列化BimFaceModel
,需要在ProjectSerializer
中使用BimFaceModelSerializer
进行嵌套序列化,具体方法请见以下代码:
class BimFaceModelSerializer(serializers.ModelSerializer):
class Meta:
model = BimFaceModel
fields = ('model_id', 'model_name', 'field_id', 'x', 'y', 'z')
class ProjectSerializer(serializers.ModelSerializer):
bimfacemodel_set = BimFaceModelSerializer(many=True, read_only=True)
class Meta:
model = Project
fields = ('project_id', 'project_name', 'project_description', 'project_img', 'project_address', 'project_price', 'project_company',
'project_area', 'project_cycle', 'project_duty_com', 'project_design_com', 'project_check_com', 'project_build_com',
'creator_id', 'create_time', 'update_id', 'update_time', 'bimfacemodel_set')
通过上述方式,可以把每个Project
对象对应的所有BimFaceModel
序列化出来并放到bimfacemodel_set
字段中。这样,就避免了N+1查询问题,在序列化数据时,也能够嵌套序列化。
django drf 改变retrive的pk查询字段
lookup_filed可以改变retrive查询时默认以pk查询的逻辑
from django.shortcuts import render from rest_framework import mixins,viewsets from .serializers import UserFavSerializer from .models import UserFav from rest_framework.permissions import IsAuthenticated # Create your views here. from rest_framework import permissions class IsOwnerOrReadOnly(permissions.BasePermission): """ Object-level permission to only allow owners of an object to edit it. Assumes the model instance has an `owner` attribute. """ def has_object_permission(self, request, view, obj): # Read permissions are allowed to any request, # so we‘ll always allow GET, HEAD or OPTIONS requests. if request.method in permissions.SAFE_METHODS: return True # Instance must have an attribute named `owner`. return obj.user == request.user class UserFavSetview(mixins.CreateModelMixin,mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin,viewsets.GenericViewSet): permission_classes = (IsAuthenticated,IsOwnerOrReadOnly) #需登陆和需要是拥有者 serializer_class = UserFavSerializer lookup_field = ‘goods_id‘ # queryset = UserFav.objects.all() def get_queryset(self): return UserFav.objects.filter(user=self.request.user)
以上是关于django开发手册DRF提升Django查询效率,你需要知道的重要操作的主要内容,如果未能解决你的问题,请参考以下文章