Django: limitare i risultati della query


Risposte:


304

I queryset di Django sono pigri. Ciò significa che una query colpirà il database solo quando si richiede specificamente il risultato.

Pertanto, fino a quando non si stampa o non si utilizza effettivamente il risultato di una query, è possibile filtrare ulteriormente senza accesso al database.

Come puoi vedere di seguito, il tuo codice esegue solo una query sql per recuperare solo gli ultimi 10 elementi.

In [19]: import logging                                 
In [20]: l = logging.getLogger('django.db.backends')    
In [21]: l.setLevel(logging.DEBUG)                      
In [22]: l.addHandler(logging.StreamHandler())      
In [23]: User.objects.all().order_by('-id')[:10]          
(0.000) SELECT "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "auth_user" ORDER BY "auth_user"."id" DESC LIMIT 10; args=()
Out[23]: [<User: hamdi>]

Ho provato questo su mongoDB e dice che SELECT non è supportato. Come fare questo su mongoDB?
— Linux,

@winux Dato che questo è specifico per Django, sembra che potresti aver bisogno di esaminare la configurazione di Django per lavorare specificamente con database di tipo Mongo / NoSQL. Questa non è una configurazione tipica nella mia esperienza, per quanto riguarda l'installazione standard di Django ORM.
— codardo anonimo il

38

In realtà penso che LIMIT 10verrebbe emesso nel database in modo che il taglio non si verificherebbe in Python ma nel database.

Vedi limiter-queryset per maggiori informazioni.


Si noti che questo non funzionerà per i queryset che necessitano anche di filtraggio, poiché non è possibile filtrare dopo lo slicing.
— Mike 'Pomax' Kamermans,

2
Quindi filtrare prima di tagliarlo. Grazie Davor per il link!
— Vyachez,

13

Sembra che la soluzione nella domanda non funzioni più con Django 1.7 e genera un errore: "Impossibile riordinare una query una volta presa una porzione"

Secondo la documentazione https://docs.djangoproject.com/en/dev/topics/db/queries/#limiting-querysets forzando il parametro "step" della sintassi della slice Python valuta la query. Funziona in questo modo:

Model.objects.all().order_by('-id')[:10:1]

Mi chiedo comunque se il limite viene eseguito in sezioni SQL o Python restituite dall'intero array di risultati. Non è utile recuperare enormi elenchi nella memoria dell'applicazione.


Anche questa soluzione non funziona con django> = 1.8 testato.
— sonus21

3

Sì. Se vuoi recuperare un sottoinsieme limitato di oggetti, puoi farlo con il codice seguente:

Esempio:

obj=emp.objects.all()[0:10]

L'inizio 0 è facoltativo, quindi

obj=emp.objects.all()[:10]

Il codice sopra riportato restituisce le prime 10 istanze.


1

Come aggiunta e osservazione alle altre risposte utili, vale la pena notare che effettivamente fare [:10]come slicing restituirà i primi 10 elementi dell'elenco , non gli ultimi 10 ...

Per ottenere gli ultimi 10 dovresti [-10:]invece fare (vedi qui ). Questo vi aiuterà a evitare di utilizzare order_by('-id')il -per invertire gli elementi.


1
Ho provato questo e ho ottenuto "L'indicizzazione negativa non è supportata".
— bparker

@DarkCygnus Product.objects.filter(~Q(price=0))[-5:]mi causa lo stesso errore: "L'indicizzazione negativa non è supportata."
— Bersam,

Questo non funziona in Django su un queryset : code.djangoproject.com/ticket/13089 Se converti il ​​queryset in un elenco funzionerà.
— valem
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.