Django: Paginator + необработанный SQL-запрос

Я использую Django Paginator везде на моем веб-сайте и даже записал специальный тег шаблона, для создания его более удобным. Но теперь я добрался до состояния, где я должен сделать сложный пользовательский необработанный SQL-запрос, это без a LIMIT возвратится о записях 100K.

Как я могу использовать 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();

Путем я использую pagintation с 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 нарезан, который является ОЧЕНЬ медленным. Как я могу заставить своего пользовательского менеджера вести себя подобный как созданный в одном?

11
задан ChillarAnand 15 April 2015 в 07:26
поделиться

2 ответа

Глядя на исходный код Paginator, в частности на функцию page () , я думаю, что это только вопрос реализации нарезки. на вашей стороне и переводит это в соответствующее предложение LIMIT в запросе SQL. Возможно, вам также понадобится добавить кеширование, но это начинает выглядеть как QuerySet, поэтому, возможно, вы можете сделать что-нибудь еще:

  • вы можете создать VIEW базы данных, используя CREATE VIEW myview AS [ваш запрос];
  • добавьте модель Django для этот ПРОСМОТР с Meta: managed = False
  • использует эту модель, как и любую другую модель, включая нарезку ее наборов запросов - это означает, что она идеально подходит для использования с Paginator

(Для вашей информации - я использовал этот подход уже давно, даже со сложными отношениями «многие ко многим», когда представления подделывают промежуточные таблицы m2m.)

9
ответ дан 3 December 2019 в 08:03
поделиться

Я не знаю о Django 1. 1, но если вы можете подождать 1.2 (которая уже не должна быть такой длинной), вы можете использовать objects.raw(), как описано в этой статье и в документации по разработке.

В противном случае, если ваш запрос не слишком сложен, возможно, будет достаточно использовать extra clause.

2
ответ дан 3 December 2019 в 08:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: