Existe alguma função Django que me permite obter um objeto do banco de dados, ou None se nada corresponder?
No momento, estou usando algo como:
foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None
Mas isso não está muito claro e é complicado ter em todos os lugares.
len(foo)
é ruim : " Observação: não use len () em QuerySets se tudo o que você deseja fazer é determinar o número de registros no conjunto. É muito mais eficiente lidar com uma contagem no nível do banco de dados, usando SELECT COUNT do SQL (), e o Django fornece um método count () precisamente por esse motivo. ". Reescrito:foo = foo[0] if foo.exists() else None
first()
: PRespostas:
No Django 1.6 você pode usar o
first()
método Queryset. Ele retorna o primeiro objeto correspondido pelo queryset, ou None se não houver nenhum objeto correspondente.Uso:
fonte
MultipleObjectsReturned()
não é gerado, como documentado aqui . Você pode encontrar algumas respostas melhores aquifirst()
obras exatamente como supor. Ele retorna o primeiro objeto no resultado da consulta e não se importa se vários resultados forem encontrados. Se você precisar verificar se há vários objetos retornados, você deve usar.get()
..get()
não é adequado para suas necessidades. A resposta correta para esta pergunta pode ser encontrada abaixo por @kaapstorm e é claramente a resposta mais adequada. Abusarfilter()
dessa forma pode levar a consequências inesperadas, algo que OP provavelmente não percebeu (a menos que eu esteja faltando alguma coisa aqui)MultipleObjectsReturned()
. Se não se espera que o resultado retornado retorne vários objetos, ele não deve ser tratado como tal. Houve um longo debate sobre isso aquiExistem duas maneiras de fazer isso;
Ou você pode usar um wrapper:
Chame assim
fonte
queryset
método para fazer isso antes de 1.6! Mas quanto a esta construção - é simplesmente desajeitada. Não é "mal" porque algum autor de tutorial da sua língua favorita disse isso. Experimente o google: "peça perdão em vez de permissão".get
método não deve retornarNone
, portanto, uma exceção faz sentido. Você deve usá-lo em situações em que tem certeza de que o objeto estará lá / o objeto "deveria" estar lá. Também usar exceções como essa é considerado 'bom' porque, bem, faz sentido. Você quer umget
com um contrato diferente, então captura a exceção e a suprime, que é a mudança que você deseja.Para adicionar um código de amostra à resposta de sorki (eu adicionaria isso como um comentário, mas esta é minha primeira postagem e não tenho reputação suficiente para deixar comentários), implementei um gerenciador personalizado get_or_none assim:
E agora posso fazer isso:
fonte
Você também pode tentar usar o django irritante (tem outras funções úteis!)
instale-o com:
fonte
Dê a Foo seu gerenciador personalizado . É muito fácil - basta colocar seu código em função no gerenciador personalizado, definir o gerenciador personalizado em seu modelo e chamá-lo com
Foo.objects.your_new_func(...)
.Se você precisar de uma função genérica (para usá-la em qualquer modelo, não apenas com o gerenciador personalizado), escreva a sua própria e coloque-a em algum lugar do caminho do Python e importe, não bagunce mais.
fonte
Seja por meio de um gerenciador ou função genérica, você também pode querer capturar 'MultipleObjectsReturned' na instrução TRY, já que a função get () levantará isso se seus kwargs recuperarem mais de um objeto.
Com base na função genérica:
e no gerente:
fonte
Aqui está uma variação da função auxiliar que permite que você opcionalmente passe em uma
QuerySet
instância, no caso de você querer obter o objeto único (se presente) de um queryset diferente dosall
objetos queryset do modelo (por exemplo, de um subconjunto de itens filhos pertencentes a um instância pai):Isso pode ser usado de duas maneiras, por exemplo:
obj = get_unique_or_none(Model, *args, **kwargs)
como previamente discutidoobj = get_unique_or_none(Model, parent.children, *args, **kwargs)
fonte
Acho que na maioria dos casos você pode apenas usar:
Somente se não for crítico que uma nova entrada seja adicionada na tabela Foo (outras colunas terão os valores Nenhum / padrão)
fonte