web-dev-qa-db-fra.com

Django - limitation des résultats de la requête

Je veux prendre les 10 dernières instances d'un modèle et avoir ce code:

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

Est-il vrai que tout d'abord ramasser toutes les instances, puis prendre seulement 10 dernières? Y a-t-il une méthode plus efficace?

169
krzyhub

Les requêtes de Django sont paresseuses. Cela signifie qu'une requête n'aboutira dans la base de données que lorsque vous demanderez spécifiquement le résultat.

Ainsi, 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 requête SQL pour ne récupérer que 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>]
265
hamdiakoguz

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

Voir limitation-querysets pour plus d'informations.

32
Davor Lucic

On dirait que la solution dans 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 Python slice La syntaxe évalue la requête. Cela fonctionne de cette façon:

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

Je me demande quand même si la limite est exécutée en SQL ou si Python coupe l'intégralité du tableau de résultats renvoyé. Il n'est pas bon de récupérer des listes énormes dans la mémoire d'application.

12
Nikolay Grischenko

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

Exemple:

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

Le début 0 est optionnel, donc

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

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

2
patel shahrukh

En guise d’ajout et d’observation aux autres réponses utiles, il convient de noter que le fait de faire [:10] ainsi que le découpage en tranches renverront les 10 premiers éléments de la liste , pas les 10 derniers ...

Pour obtenir les 10 derniers, vous devriez plutôt faire [-10:] (voir ici ). Cela vous aidera à éviter d'utiliser order_by('-id') avec le - pour inverser les éléments.

1
DarkCygnus