我在我的网站上到处都使用Django Paginator,甚至编写了一个特殊的模板标签,以使其更加方便。但是现在我进入一种状态,需要进行一个复杂的自定义原始SQL查询,如果没有LIMIT,它将返回大约10万条记录。

如何在自定义查询中使用Django Pagintor?

我的问题的简化示例:

我的模特:

class PersonManager(models.Manager):

    def complicated_list(self):

        from django.db import connection

        #Real query is much more complex
        cursor.execute("""SELECT * FROM `myapp_person`""");

        result_list = []

        for row in cursor.fetchall():
            result_list.append(row[0]);

        return result_list


class Person(models.Model):
    name      = models.CharField(max_length=255);
    surname   = models.CharField(max_length=255);
    age       = models.IntegerField();

    objects   = PersonManager();

我在Django ORM中使用分页的方式:
all_objects = Person.objects.all();

paginator = Paginator(all_objects, 10);

try:
    page = int(request.GET.get('page', '1'))
except ValueError:
    page = 1

try:
    persons = paginator.page(page)
except (EmptyPage, InvalidPage):
    persons = paginator.page(paginator.num_pages)

这样,Django变得非常聪明,并在执行查询时将LIMIT添加到查询中。但是当我使用自定义管理器时:
all_objects = Person.objects.complicated_list();

所有数据都被选中,然后才对python list进行切片,这非常慢。如何使自定义管理器的行为类似于内置管理器?

最佳答案

查看Paginator的源代码,尤其是page() function,我认为这只是在您这一边实现slicing并将其转换为SQL查询中的相关LIMIT子句的问题。您可能还需要添加一些缓存,但是开始看起来像QuerySet,所以也许您可以做其他事情:

  • 您可以使用CREATE VIEW myview AS [您的查询]创建数据库VIEW;
  • 为该 View 添加Django模型,并添加Meta: managed=False
  • 与其他任何模型一样使用该模型,包括对其查询集进行切片-这意味着它非常适合与Paginator
  • 一起使用

    (供您引用-我已经使用这种方法很长时间了,即使与VIEWs的复杂多对多关系伪造了m2m中间表。)

    10-07 16:04
    查看更多