Django - limitation des résultats de requête


Réponses:


304

Les ensembles de requêtes Django sont paresseux. Cela signifie qu'une requête atteindra la base de données uniquement lorsque vous demanderez spécifiquement le résultat.

Donc, jusqu'à ce que vous imprimiez ou utilisiez réellement le résultat d'une requête, vous pouvez filtrer davantage sans accès à la base de données.

Comme vous pouvez le voir ci-dessous, votre code n'exécute qu'une seule requête SQL pour récupérer uniquement les 10 derniers éléments.

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>]

J'ai essayé cela sur mongoDB et il est dit que SELECT n'est pas pris en charge. Comment faire cela sur mongoDB?
winux

@winux Étant donné que cela est spécifique à Django, il semble que vous deviez peut-être envisager de configurer Django pour qu'il fonctionne spécifiquement avec les bases de données de type Mongo / NoSQL. Ce n'est pas une configuration typique dans mon expérience, en ce qui concerne la configuration standard de Django ORM.
lâche anonyme

38

En fait, je pense que le LIMIT 10serait délivré à la base de données afin que le découpage ne se produise pas en Python mais dans la base de données.

Voir limitation-querysets pour plus d'informations.


Notez que cela ne fonctionnera pas pour les ensembles de requêtes qui nécessitent également un filtrage, car vous ne pouvez pas filtrer après le découpage.
Mike 'Pomax' Kamermans

2
Donc, filtrez d'abord que coupez-le. Merci Davor pour le lien!
Vyachez

13

Il semble que la solution de la question ne fonctionne plus avec Django 1.7 et génère une erreur: "Impossible de réorganiser une requête une fois qu'une tranche a été prise"

Selon la documentation https://docs.djangoproject.com/en/dev/topics/db/queries/#limiting-querysets forçant le paramètre «step» de la syntaxe de tranche Python évalue la requête. Cela fonctionne de cette façon:

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

Je me demande toujours si la limite est exécutée dans des tranches SQL ou Python, le tableau de résultats entier retourné. Il ne sert à rien de récupérer d'énormes listes dans la mémoire de l'application.


Même cette solution ne fonctionne pas avec django> = 1.8 testé.
sonus21

3

Oui. Si vous souhaitez récupérer un sous-ensemble limité d'objets, vous pouvez le faire avec le code ci-dessous:

Exemple:

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

Le début 0 est facultatif, donc

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

Le code ci-dessus renvoie les 10 premières instances.


1

Comme ajout et observation aux autres réponses utiles, il convient de noter qu'en réalité, le fait [:10]de trancher renvoie les 10 premiers éléments de la liste , pas les 10 derniers ...

Pour obtenir les 10 derniers, vous devez faire à la [-10:]place (voir ici ). Cela vous évitera d'utiliser order_by('-id')avec le -pour inverser les éléments.


1
J'ai essayé cela et j'ai obtenu "L'indexation négative n'est pas prise en charge."
bparker

@DarkCygnus Product.objects.filter(~Q(price=0))[-5:]me cause la même erreur: "L'indexation négative n'est pas prise en charge."
bersam

Cela ne fonctionne pas dans django sur un ensemble de requêtes: code.djangoproject.com/ticket/13089 Si vous convertissez l'ensemble de requêtes en liste, cela fonctionnera.
valem
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.