Qual é a maneira correta de validar se um objeto existe em uma visão django sem retornar 404?

91

Preciso verificar se existe um objeto e retornar o objeto, então com base nisso realizo ações. Qual é a maneira certa de fazer isso sem retornar um 404?

try:
    listing = RealEstateListing.objects.get(slug_url = slug)
except:
    listing = None

if listing:
Rasiel
fonte
Rasiel, posso sugerir que você aceite a outra resposta? Parece ser a maneira correta de fazer isso, e foi bem mais votado do que a resposta aceita.
Azendale de
1
Posso considerar, porém existe foi introduzido no Django 1.2 que foi lançado em 17 de maio de 2010, Se você perceber que minha pergunta foi enviada em 09 ... esta era a resposta correta na época. Se Exists () agora for considerado a melhor maneira de fazer isso, acho que seria semanticamente correto escolher a segunda resposta, certo?
Rasiel
Rasiel, faz sentido que essa seja a resposta correta na hora. Mas os sites stackoverflow parecem ser tanto sobre a construção de um conjunto de perguntas boas / oficiais com as melhores respostas quanto os sites estão encontrando soluções para os problemas das pessoas. Daí minha sugestão de selecionar o que agora é a resposta "oficialmente correta".
Azendale
O if listing:deve ser um else:.
Crônico de

Respostas:

116

Eu não usaria o wrapper 404 se você não recebesse um 404. Isso é um uso indevido de intenção. Apenas pegue o DoesNotExist, em vez disso.

try:
    listing = RealEstateListing.objects.get(slug_url=slug)
except RealEstateListing.DoesNotExist:
    listing = None
rã de ferro
fonte
+1: Sim, esta é uma solução melhor do que a aceita, se você não quiser o 404.
Carl Meyer,
yap, esta parece ser a melhor solução
Rasiel
3
Essa solução funciona melhor do que exists()se você precisar fazer algo com o objeto.
SaeX de
2
Gosto de acrescentar values_list('id', flat=True). se eu preciso apenas ver se existelisting = RealEstateListing.objects.values_list('id', flat=True).get(slug_url=slug)
erajuan
O que acho estranho nessa sintaxe é que RealEstateListing.DoesNotExistse refere ao modelo, e não ao objeto em si. Por que não é RealEstateListing.objects.get(slug_url=slug).DoesNotExist?
Maxim Vallee
198

Você também pode fazer:

if not RealEstateListing.objects.filter(slug_url=slug).exists():
    # do stuff...

Às vezes é mais claro usar o try: except:bloco e outras vezes uma linha exists()torna o código mais claro ... tudo depende da lógica da sua aplicação.

zzart
fonte
7
esta é a melhor maneira e deveria ter a resposta
Jharwood
3
Estou assumindo que exists()não funciona com get(), certo?
Eduard Luca
8
Observe que esta solução só é válida se você não for usar o objeto em questão. Caso contrário (como na situação de OPs) está errado e muito mais lento do que a solução aceita: Se você fizer um get()mais tarde, ele enviará uma segunda consulta ao banco de dados.
Crônico de
1
Se você está verificando a existência de fazer algo com o objeto (se existir), então eu vou preferir try-exceptmais exists().
Jithin Pavithran
7
listing = RealEstateListing.objects.filter(slug_url=slug).first() 
Henrik Heino
fonte
2
Esta é a melhor solução se você precisar usar o objeto potencial mais tarde, uma vez que requer apenas uma atribuição e evita ter que usar um bloco try / except. Observe que você pode testar a existência mais tarde simplesmente comif listing:
Michael Hays
Evitar try / except é uma má prática. Um dos aspectos mais importantes do Desenvolvimento de Software é a disponibilidade para controlar as Exceções, para poder proporcionar uma boa experiência ao usuário. Avise as pessoas quando algo não estiver funcionando corretamente. Segundo; se você quiser testar a existência de um QuerySet, use .exists (), caso contrário, é um objeto. Teste a existência com sua chave primária .... if object.pk: // run code () Esta consulta é muito mais rápida do que recuperar todos os dados do objeto. Você só quer saber se existe.
Wolfgang Leon
2
Já existia uma solução usando try / except e .exists(). Acho que é uma boa ideia no SO ter várias respostas diferentes sobre como fazer as coisas. Talvez seja melhor para quem também deseja utilizar o objeto caso ele exista. Eu não faria nenhuma regra se try / except devesse ser evitado ou não. Às vezes é bom e às vezes é ruim, por exemplo, se você deseja apenas fazer um código muito compacto.
Henrik Heino
0

Eu faria da seguinte forma:

listing = RealEstateListing.objects.filter(slug_url=slug)
if listing:
    # do stuff

Não vejo necessidade de try / catch. Se houver potencialmente vários objetos no resultado, use first () conforme mostrado pelo usuário Henrik Heino

Greg Holst
fonte
A menos que você faça um .first () no conjunto de consultas ou um .first () na condicional, isso sempre retornará True.
B.Adler 01 de