Python 在Django REST ListAPI视图中分页原始SQL查询的最佳方法?

Python 在Django REST ListAPI视图中分页原始SQL查询的最佳方法?,python,sql,django,pagination,django-rest-framework,Python,Sql,Django,Pagination,Django Rest Framework,我有一个原始SQL查询,用于为Django REST ListAPI视图构建查询集。大致如下,请原谅那些毫无意义的名字: class MyView(ListAPIView): serializer_class = MySerializer paginate_by = 10 def get_queryset(self): params = { "uid": str(self.request.user.id),

我有一个原始SQL查询,用于为Django REST ListAPI视图构建查询集。大致如下,请原谅那些毫无意义的名字:

class MyView(ListAPIView):
    serializer_class = MySerializer
    paginate_by = 10
    def get_queryset(self):
        params = {
            "uid": str(self.request.user.id),
            "param": str(self.kwargs['param'])
        }
        query = 'SELECT f.id ' \
            'FROM myapp_foo f, myapp_bar b ' \
            'WHERE b.foo_id = f.id AND ' \
            'b.param >= %(param)s AND ' \
            'f.dt_tm >= NOW() AND ' \
            '(SELECT COUNT(*) FROM myapp_baz z ' \
            'WHERE z.user_id = %(uid)s AND ' \
            'z.qux_id = f.qux_id) = 0 ' \
            'ORDER BY f.dt_tm;'
        return Foo.objects.raw(query, params)
这会产生以下错误:

object of type 'RawQuerySet' has no len()
我希望使用类似的SQL查询计算计数,然后使用LIMIT和OFFSET参数进行分页。我读过一些建议,其中列表项被计数以获得len,但这似乎并不令人满意,因为除非查询中有一个小的限制,否则这将是低效的,在任何情况下都会破坏分页的目的

更新: 我刚刚注意到paginate_by正在等待弃用


首先,如何向返回的对象添加计数方法?

如果在返回原始查询集之前将其强制转换为列表,则应防止“RawQuerySet”没有len错误

正如您所说,这将是低效的,因为它将加载整个queryset


可以编写一个自定义分页类,使用limit和offset有效地分页,并在视图中与属性一起使用。

如果在返回原始查询集之前将其强制转换为列表,则应防止“RawQuerySet”没有len错误

正如您所说,这将是低效的,因为它将加载整个queryset


可以编写一个自定义分页类,使用limit和offset高效地分页,并在视图中使用该类的属性。

比其他替代方法更有效的解决方案是编写自己的RawQuerySet替换。我正在显示下面的代码,但您也可以。绝对不能保证没有错误;尽管如此,我还是在Python3上的Django 1.11中使用它,并使用PostgreSQL作为数据库;也应该使用MySQL。简单地说,这个类将相应的LIMIT和OFFSET子句添加到原始SQL查询中。没有什么疯狂的,只是一些简单的字符串连接,所以请确保不要在原始SQL查询中包含这些子句

班级 自定义分页类 为了完成,我还包括一个分页类:

from rest_framework.pagination import PageNumberPagination


class MyModelResultsPagination(PageNumberPagination):
    """Fixed page-size pagination with 10 items."""
    page_size = 10
    max_page_size = 10
您的ListAPIView 一句警告的话 PaginatedRawQuerySet类虽然对我来说很有用,但还没有经过广泛的测试,但我相信它确实提供了一个解决方案的概念,该解决方案比为每次调用选择queryset中的所有项更有效

您可能会注意到,RawQuerySet中最初缺少一个自定义计数方法实现,它是通过调用self.model.objects.count来计算的。如果没有这种方法,paginator将评估lenyour_raw_queryset,这将对性能产生与其他答案相同的影响

这个类并不是RawQuerySet的一刀切的替代品,这意味着您应该添加自己的定制以使其适合您的需要


例如,如果您需要更复杂的内容,您可以向PaginatedRawQuerySet类添加另一个属性,称为raw_count_query,该属性随后将被称为inside count,而不是像现在这样对所有对象进行计数,这将在需要过滤的情况下使用;raw_count_查询将根据您的条件提供对子集进行计数的SQL。

比其他替代方法更有效的解决方案是编写自己的RawQuerySet替换。我正在显示下面的代码,但您也可以。绝对不能保证没有错误;尽管如此,我还是在Python3上的Django 1.11中使用它,并使用PostgreSQL作为数据库;也应该使用MySQL。简单地说,这个类将相应的LIMIT和OFFSET子句添加到原始SQL查询中。没有什么疯狂的,只是一些简单的字符串连接,所以请确保不要在原始SQL查询中包含这些子句

班级 自定义分页类 为了完成,我还包括一个分页类:

from rest_framework.pagination import PageNumberPagination


class MyModelResultsPagination(PageNumberPagination):
    """Fixed page-size pagination with 10 items."""
    page_size = 10
    max_page_size = 10
您的ListAPIView 一句警告的话 PaginatedRawQuerySet类虽然对我来说很有用,但还没有经过广泛的测试,但我相信它确实提供了一个解决方案的概念,该解决方案比为每次调用选择queryset中的所有项更有效

您可能会注意到,RawQuerySet中最初缺少一个自定义计数方法实现,它是通过调用self.model.objects.count来计算的。如果没有这种方法,paginator将评估lenyour_raw_queryset,这将对性能产生与其他答案相同的影响

这个类并不是RawQuerySet的一刀切的替代品,这意味着您应该添加自己的定制以使其适合您的需要

例如,如果您需要更复杂的内容,您可以向PaginatedRawQuerySet类添加另一个属性,称为raw_count_query,该属性随后将被称为inside count,而不是像现在这样对所有对象进行计数,这将在需要过滤的情况下使用;拉乌公司
unt\U查询将提供SQL,以根据您的条件计算子集。

我也有同样的问题,我刚刚发现使用raw可以使用额外的:

(...)
return Foo.objects.extra(where=query, params=params) 
附加变量

where=['data->>"$.SOMETHING" = %s OR data->>"$.SOMETHING" = %s OR data->>"$.SOMETHING" = %s', 'data->>"$.GROUP" LIKE %s'] 
params=['EX1', 'EX2', 'EX3', '%EXEMPLE4%']

注意:主要问题是使用与QuerySet具有相同属性的RawQuerySet,如果可能的话,最好的方法是使用QuerySet API的额外部分

我也遇到了同样的问题,我只是发现使用raw可以使用额外的:

(...)
return Foo.objects.extra(where=query, params=params) 
附加变量

where=['data->>"$.SOMETHING" = %s OR data->>"$.SOMETHING" = %s OR data->>"$.SOMETHING" = %s', 'data->>"$.GROUP" LIKE %s'] 
params=['EX1', 'EX2', 'EX3', '%EXEMPLE4%']

注意:主要问题是使用与QuerySet具有相同属性的RawQuerySet,如果可能的话,最好的方法是使用QuerySet API的额外部分

我认为使用上限会限制查询集的大小。到目前为止,我还没有找到一个使用原始SQL查询进行自定义分页的好例子,我想使用上限会限制查询集的大小。到目前为止,我还没有找到一个使用原始SQL查询进行自定义分页的好例子。非常详细,说明也很好!非常详细和指导!
where=['data->>"$.SOMETHING" = %s OR data->>"$.SOMETHING" = %s OR data->>"$.SOMETHING" = %s', 'data->>"$.GROUP" LIKE %s'] 
params=['EX1', 'EX2', 'EX3', '%EXEMPLE4%']