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.