正确使用视图集查询集

时间:2018-07-07 06:03:55

标签: django django-rest-framework

根据Django REST framework documentation,以下两个代码段的行为应相同。

class UserViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing or retrieving users.
    """
    def list(self, request):
        queryset = User.objects.all()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = User.objects.all()
        user = get_object_or_404(queryset, pk=pk)
        serializer = UserSerializer(user)
        return Response(serializer.data)
class UserViewSet(viewsets.ModelViewSet):
    """
    A viewset for viewing and editing user instances.
    """
    serializer_class = UserSerializer
    queryset = User.objects.all()

但是我的解释方式是,在第一种情况下,查询User.objects.all()与每个api调用一起运行,在第二种情况下,查询在Web服务器启动时仅运行一次,因为它是类变量。我错了吗 ?至少在我的测试中,尝试模拟User.objects.all将会失败,因为到那时UserViewSet.queryset将已经是一个空的Queryset对象。

请有人向我解释为什么不应该避免使用queryset类参数(例如使用pest和get_queryset代替)? 编辑:用get_queryset替换queryset会使self.queryset在检索方法中未定义,所以我也需要在方法内使用self.get_queryset()...

2 个答案:

答案 0 :(得分:2)

  1. 您错了,Django查询是惰性的,因此在两种情况下查询都将在响应时间运行

来自Django docs

  

QuerySet是惰性的–创建QuerySet的行为不涉及任何数据库活动。您可以整天将过滤器堆叠在一起,并且在评估QuerySet之前,Django不会真正运行查询

  1. ModelViewSet提供了诸如deleteupdate之类的其他操作,您可能需要针对用户模型对它们进行一些限制(例如检查权限,或者您可能不喜欢让用户只需删除其个人资料)

  2. self.queryset用于路由器以及基本名称和内容,您可以忽略它并在路由器中手动设置基本名称。它不是强制性的,但我认为它使我的代码更具可读性

请注意,当您要对默认查询集执行某些操作(例如基于当前用户的限制def get_queryset)时,通常使用self.queryset。因此,如果get_queryset要返回.objects.all().objects.filter(active=True),我建议使用self.queryset来获得更简洁的代码

note2:如果您决定定义get_queryset,我建议也定义self.queryset(如果可能)

note3:始终在视图方法中使用self.get_queryset,即使您未定义此方法,您可能也需要稍后创建该方法,如果您的视图方法使用self.queryset,则可能会导致您代码中的一些问题

答案 1 :(得分:0)

添加到 Aliva 的 answer 并引用 DRF 视图集代码,在 get_queryset() 方法定义下它指出:

<块引用>

应始终使用此方法而不是访问 self.queryset 直接,因为 self.queryset 仅被评估一次,并且这些结果 为所有后续请求缓存。如果您需要提供不同的 查询集取决于传入的请求。