Django: Paginator + raw-SQL-Abfrage
Bin ich mit Django Paginator überall auf meiner website und schrieb sogar einen speziellen template tag, um zu machen es bequemer. Aber jetzt habe ich zu einem Zustand, wo ich brauche, um eine komplexe custom raw-SQL-Abfrage, die ohne LIMIT
zurück über 100K Datensätze.
Wie kann ich mit Django Pagintor mit benutzerdefinierten Abfrage?
Vereinfachtes Beispiel für mein problem:
Mein Modell:
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();
Die Art, wie ich pagintation mit 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)
Diese Weise, Django sehr smart und fügt LIMIT
zu einer Abfrage bei der Ausführung. Aber wenn ich custom manager:
all_objects = Person.objects.complicated_list();
alle Daten ausgewählt werden, und nur dann python-Liste ist in Scheiben geschnitten, was SEHR langsam ist. Wie kann ich meine custom-manager Verhalten sich ähnlich wie die eingebauten in einem?
- In Python, sollten Sie nicht verwenden Leerzeichen, wenn Sie so wollen, in Ihrer Person-Klasse.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Blick auf Paginator source-code, Seite () - Funktion in allem denke ich, dass es nur um die Umsetzung schneiden auf Ihrer Seite, und zu übersetzen, die zu den relevanten LIMIT-Klausel in der SQL-Abfrage. Möglicherweise müssen Sie auch hinzufügen, einige Zwischenspeichern, aber diese beginnt zu schauen, wie QuerySet, so können Sie vielleicht etwas anderes tun:
(Für Ihre Informationen - ich habe mit diesem Konzept für eine lange Zeit jetzt, auch mit komplexen viele-zu-viele-Beziehungen mit Blick auf faking m2m-intermediate-Tabellen.)
Ich weiß nicht, über Django 1.1 aber wenn Sie warten können für 1.2 (das sollte nicht sein, dass schon lange nicht mehr) Sie können Gebrauch machen von
objects.raw()
wie beschrieben in dieser Artikel und in der Entwicklung Dokumentation.Sonst, wenn Sie die Abfrage nicht zu Komplex, vielleicht mit
extra
- Klausel ist ausreichend.Hier ist ein
RawPaginator
Klasse, ich habe das überschreibtPaginator
arbeiten mit raw-Abfragen. Es braucht ein zusätzliches argument,count
, die die Gesamtzahl Ihrer Abfrage. Es muss nicht schneiden Sie dieobject_list
da müssen Sie den Umbruch in Ihrem raw-query überOFFSET
undLIMIT
.count
nehmen, wenn als argument mitgegeben?Wollte ich auch Stecker a
PaginatedRawQuerySet
was ich geschrieben habe (bitte betrachten Sie dies als eine alpha-version). Dieses fügt dem slicing-Fähigkeit, eine raw-queryset. Bitte diese Antwort – das schrieb ich für eine andere Frage mit einer ähnlichen Anforderung – um zu verstehen, wie es funktioniert (vor allem die "Achtung" - Abschnitt am Ende).