Django - limitando resultados da consulta


Respostas:


304

Os querysets do Django são preguiçosos. Isso significa que uma consulta atingirá o banco de dados somente quando você solicitar especificamente o resultado.

Portanto, até que você imprima ou use realmente o resultado de uma consulta, poderá filtrar ainda mais sem acesso ao banco de dados.

Como você pode ver abaixo, seu código executa apenas uma consulta sql para buscar apenas os últimos 10 itens.

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

Eu tentei isso no mongoDB e diz SELECT não suportado. Como fazer isso no mongoDB?
winux 2/01/19

@winux Como isso é específico do Django, parece que você pode precisar configurar o Django para trabalhar especificamente com bancos de dados do tipo Mongo / NoSQL. Essa não é uma configuração típica em minha experiência, com relação à configuração padrão do Django ORM.
covarde anônimo

38

Na verdade, acho que o LIMIT 10seria emitido para o banco de dados, para que o fatiamento não ocorresse no Python, mas no banco de dados.

Veja limit-querysets para mais informações.


Observe que isso não funcionará para conjuntos de consultas que também precisam de filtragem, pois você não pode filtrar após o fatiamento.
Mike 'Pomax' Kamermans

2
Portanto, filtre primeiro que cortá-lo. Obrigado Davor pelo link!
Vyachez 26/07/19

13

Parece que a solução na pergunta não funciona mais com o Django 1.7 e gera um erro: "Não é possível reordenar uma consulta depois que uma fatia foi feita"

De acordo com a documentação https://docs.djangoproject.com/en/dev/topics/db/queries/#limiting-querysets forçando o parâmetro "step" da sintaxe de fatia do Python, avalia a consulta. Funciona assim:

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

Ainda me pergunto se o limite é executado em fatias SQL ou Python, toda a matriz de resultados retornada. Não é bom recuperar listas enormes para a memória do aplicativo.


Mesmo esta solução não funciona com django> = 1.8 testado.
sonus21

3

Sim. Se você deseja buscar um subconjunto limitado de objetos, é possível com o código abaixo:

Exemplo:

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

O começo 0 é opcional, então

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

O código acima retorna as 10 primeiras instâncias.


1

Como uma adição e observação para as outras respostas úteis, vale a pena notar que, na verdade, fazer [:10]o fatiamento retornará os 10 primeiros elementos da lista , não os últimos 10 ...

Para obter os últimos 10, você deve fazê-lo [-10:](veja aqui ). Isso ajudará a evitar o uso order_by('-id')com o -para reverter os elementos.


1
Eu tentei isso e obtive "A indexação negativa não é suportada".
bparker

@DarkCygnus Product.objects.filter(~Q(price=0))[-5:]me causa o mesmo erro: "A indexação negativa não é suportada."
bersam

Isso não funciona no django em um conjunto de consultas : code.djangoproject.com/ticket/13089 Se você converter o conjunto de consultas em uma lista, ele funcionará.
valem 9/01
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.