django 当重写get_queryset时计算QuerySet时

nbysray5  于 2023-03-24  发布在  Go
关注(0)|答案(2)|浏览(126)

我不太明白QS在被重写时是如何被求值的。基于leedjango问题,我们可以在一个视图类中重写get_queryset。在这个例子中,我不太明白get_queryset方法何时返回QS求值。我们知道QS通常是如何被求值的,正如在eugene问题中所解释的那样。
例如,我有以下组件:前端将GET请求发送到适当的URL:

//Dashboard.js:
export default function Dashboard() {
    const [tableData, setTableData] = useState([]);
    const getUserSchools = () => {
        getUser({ email: keycloak.email }).then((response) => {
          const { data: users } = response;
          if (users.length) {
            const appUser = users[0];
            axios
              .get(`/api/school/list/?user_id=${appUser.id}`)
              .then((data) => {
                setTableData(data.data.results);
              })
              .catch((err) => {
                /* eslint-disable-next-line */
                console.error(err);
                setTableData([]);
              });
          }
        });
      };

然后,它访问school-urls.py,查找与该URL相关的视图:

urlpatterns = [
    url(r"^list/$", SchoolsList.as_view()),
]

SchoolsList是覆盖get_queryset并返回queryset的适当视图:

#list.py
class LargeResultsSetPagination(pagination.PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 100
    
class SchoolsList(generics.ListAPIView):
    pagination_class = LargeResultsSetPagination
    serializer_class = SchoolGetSerializer

    def get_queryset(self):
        queryset = School.objects.all()
        
        user_id = self.request.query_params.get('user_id', None)
        if (user_id is not None):
            queryset = queryset.filter(user_id=user_id)
        
        return queryset.order_by('id')

使用以下序列化程序:

#get.py
class SchoolGetSerializer(serializers.ModelSerializer):
    nearest_community = SchoolCommunitySerializer(required=False)
    nearest_post_secondary = SchoolPostSecondarySerializer(required=False)
    regional_district = SchoolRegionalDistrictSerializer(required=False)

    class Meta:
        model = School
        fields = (
            "id",
            "address",
            "nearest_post_secondary",
            "nearest_community",
            "regional_district",
        )

在上面的代码片段中,当查询集被求值时?
当从前端或 Postman 发送GET请求时,我可以看到返回了两次queryset,第一次几乎立即返回queryset。但是,GET请求直到50秒后才完成,再次计算并返回queryset(在这里我不知道如何计算)。手动执行的查询延迟750ms。这不是一个繁重的查询,它只是通过id选择一个记录。
你知道为什么get_queryset被命中并立即返回而不执行queryset,然后在50秒后查询数据库吗?我如何立即强制查询数据库?

**编辑:**QuerySet在执行Serializer之前会被求值,如果nearest_community和nearest_post_secondary字段有大量的查询,那么执行QuerySet会延迟,如果你只是简单的执行Serializer,那么你会立即得到响应。

谢谢

hkmswyz6

hkmswyz61#

问题不在于查询,问题在于序列化器需要进行额外的查询来获取相关的对象。你应该在同一个查询中加载这些元素,使用**``**:

class SchoolsList(generics.ListAPIView):
    pagination_class = LargeResultsSetPagination
    serializer_class = SchoolGetSerializer

    def get_queryset(self):
        queryset = School.objects.all()

        user_id = self.request.query_params.get('user_id')
        if user_id is not None:
            queryset = queryset.filter(user_id=user_id)

        return queryset.select_related(
            'nearest_community', 'nearest_post_secundary', 'regional_district'
        ).order_by('id')

由于这些序列化程序可能会查询其他项,因此您甚至可能应该选择其他字段,但这些字段在您的问题中没有提到。

uelo1irk

uelo1irk2#

查询集是惰性的,它们在你使用的时候被计算,而不是在你过滤、排序等等的时候(参见ModelManagers),使用它可以轻松进行批量管理(您的查询)。您需要检查连接到数据库的数量,特别是在循环中。这非常重要(不要做假设). Model.object.get_values()for get dictionaries可能会导致额外的成本,例如,您可以编写特定的Manager来修复它。如果您需要单独的东西,请使用模型方法。
我回答你的问题了吗?
这是错误的:

return queryset.order_by('id')

你做不到。查询还没完成。至少,做一下:

from django.http import JsonResponse
# code, code, code...

def any_view(request):
    # code, code, code...
    response = {'data': queryset.order_by('id').values()}
    return JsonResponse(response)

相关问题