Freqüentemente me pego querendo pegar o primeiro objeto de um queryyset no Django, ou retornar None
se não houver nenhum. Existem muitas maneiras de fazer isso que funcionam. Mas estou me perguntando qual é o mais eficiente.
qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
return qs[0]
else:
return None
Isso resulta em duas chamadas ao banco de dados? Isso parece um desperdício. Isso é mais rápido?
qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
return qs[0]
else:
return None
Outra opção seria:
qs = MyModel.objects.filter(blah = blah)
try:
return qs[0]
except IndexError:
return None
Isso gera uma única chamada ao banco de dados, o que é bom. Mas requer a criação de um objeto de exceção a maior parte do tempo, o que exige muita memória quando tudo o que você realmente precisa é de um teste-se trivial.
Como posso fazer isso com apenas uma chamada de banco de dados e sem agitar a memória com objetos de exceção?
len()
em conjuntos de consultas, sempre use.count()
.first()
elast()
conveniência métodos: docs.djangoproject.com/en/dev/ref/models/querysets/#firstRespostas:
O Django 1.6 (lançado em novembro de 2013) introduziu os métodos de conveniência
first()
elast()
que engolem a exceção resultante e retornamNone
se o conjunto de consultas não retornar objetos.fonte
first()
elast()
imponha umaORDER BY
cláusula em uma consulta. Isso tornará os resultados determinísticos, mas provavelmente reduzirá a velocidade da consulta.A resposta correta é
Que pode ser usado em:
Você não gostaria de transformá-lo em uma lista, porque isso forçaria uma chamada de banco de dados completa de todos os registros. Basta fazer o acima e ele puxará apenas o primeiro. Você pode até usar
.order_by
para garantir o primeiro que deseja.Certifique-se de adicionar o
.get()
ou você receberá um QuerySet de volta e não um objeto.fonte
Entry.objects.all()[0]
??fonte
LIMIT 1
à consulta e não sei se você pode fazer melhor do que isso. No entanto, internamente__nonzero__
naQuerySet
é implementado comotry: iter(self).next() except StopIteration: return false...
para que ele não escapa a exceção.QuerySet.__nonzero__()
nunca é chamado, pois oQuerySet
é convertido em umlist
antes de verificar a veracidade. Outras exceções ainda podem ocorrer no entanto.StopIteration
exceção.__iter__
para obter um novo objeto iterador e chamar seunext
método até queStopIteration
seja lançada. Então, definitivamente não vai ser uma exceção em algum lugar;)Agora, no Django 1.9, você tem um
first()
método para conjuntos de consultas.Essa é uma maneira melhor do que
.get()
ou[0]
porque ela não gera uma exceção se o conjunto de consultas estiver vazio. Portanto, você não precisa verificar usandoexists()
fonte
Se você planeja obter o primeiro elemento com frequência - você pode estender o QuerySet nesta direção:
Defina o modelo assim:
E use-o assim:
fonte
Isso também poderia funcionar:
se estiver vazio, retornará uma lista vazia, caso contrário, ele retornará o primeiro elemento dentro de uma lista.
fonte
Pode ser assim
ou
fonte
Você deve usar métodos django, como existe. Está lá para você usá-lo.
fonte
Desde o django 1.6, você pode usar filter () com o método first () da seguinte forma:
fonte