Django & DRF中get_queryset被调用两次,有无更优解决方案?
Django REST Framework中get_queryset重复调用问题
我用Django和REST Framework搭建API项目时遇到个问题:使用DRF通用视图+DjangoModelPermissions编写视图时,get_queryset方法会被调用两次。调试后发现,权限验证环节会调用get_queryset来获取模型以校验用户权限,这属于不必要的操作,数据表较大时会引发性能问题。
现有代码
权限类
class DefaultModelPermissions(DjangoModelPermissions): """ 使用django.contrib.auth权限做认证,确保用户已登录且拥有对应模型的view/add/change/delete权限 仅适用于提供了.queryset属性的视图类 """ perms_map = { 'GET': ['%(app_label)s.view_%(model_name)s'], 'OPTIONS': ['%(app_label)s.view_%(model_name)s'], 'HEAD': ['%(app_label)s.view_%(model_name)s'], 'POST': ['%(app_label)s.add_%(model_name)s'], 'PUT': ['%(app_label)s.change_%(model_name)s'], 'PATCH': ['%(app_label)s.change_%(model_name)s'], 'DELETE': ['%(app_label)s.delete_%(model_name)s'], } class DefaultModelViewPermissions: permission_classes = (DefaultModelPermissions,)
视图类
class AgentListCreateView(DefaultModelViewPermissions, generics.ListCreateAPIView): serializer_class = serializers.AgentSerializer def get_queryset(self): print('get_queryset') return models.Agent.objects.all()
当前解决方案
我重写了has_permission方法,直接从序列化器的Meta类中获取模型,避免调用get_queryset触发不必要的数据库查询:
class DefaultModelPermissions(DjangoModelPermissions): """ 使用django.contrib.auth权限做认证,确保用户已登录且拥有对应模型的view/add/change/delete权限 仅适用于提供了.queryset属性的视图类 """ perms_map = { 'GET': ['%(app_label)s.view_%(model_name)s'], 'OPTIONS': ['%(app_label)s.view_%(model_name)s'], 'HEAD': ['%(app_label)s.view_%(model_name)s'], 'POST': ['%(app_label)s.add_%(model_name)s'], 'PUT': ['%(app_label)s.change_%(model_name)s'], 'PATCH': ['%(app_label)s.change_%(model_name)s'], 'DELETE': ['%(app_label)s.delete_%(model_name)s'], } def has_permission(self, request, view): if not request.user or ( not request.user.is_authenticated and self.authenticated_users_only): return False # 避免DefaultRouter的根视图应用权限校验 if getattr(view, '_ignore_model_permissions', False): return True # 从序列化器获取模型,避免调用get_queryset触发数据库查询 if hasattr(view, 'get_serializer_class'): model = view.get_serializer_class().Meta.model else: model = view.serializer_class.Meta.model perms = self.get_required_permissions(request.method, model) return request.user.has_perms(perms)
疑问
想问下有没有更优的解决办法?其他开发者也遇到过这个问题吗?
内容的提问来源于stack exchange,提问作者Chinellow
相关产品推荐
相关产品推荐

