Я использую 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 нарезан, который является ОЧЕНЬ медленным. Как я могу заставить своего пользовательского менеджера вести себя подобный как созданный в одном?
Глядя на исходный код Paginator, в частности на функцию page () , я думаю, что это только вопрос реализации нарезки. на вашей стороне и переводит это в соответствующее предложение LIMIT в запросе SQL. Возможно, вам также понадобится добавить кеширование, но это начинает выглядеть как QuerySet, поэтому, возможно, вы можете сделать что-нибудь еще:
(Для вашей информации - я использовал этот подход уже давно, даже со сложными отношениями «многие ко многим», когда представления подделывают промежуточные таблицы m2m.)
Я не знаю о Django 1. 1, но если вы можете подождать 1.2 (которая уже не должна быть такой длинной), вы можете использовать objects.raw()
, как описано в этой статье и в документации по разработке.
В противном случае, если ваш запрос не слишком сложен, возможно, будет достаточно использовать extra
clause.