¿Hay alguna función de Django que me permita obtener un objeto de la base de datos, o Ninguno si nada coincide?
Ahora mismo estoy usando algo como:
foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None
Pero eso no está muy claro y es complicado tenerlo en todas partes.
len(foo)
es malo : " Nota: No use len () en QuerySets si todo lo que quiere hacer es determinar la cantidad de registros en el conjunto. Es mucho más eficiente manejar un recuento a nivel de base de datos, usando SELECT COUNT de SQL (), y Django proporciona un método count () precisamente por esta razón. ". Reescrito:foo = foo[0] if foo.exists() else None
first()
: PRespuestas:
En Django 1.6 puedes usar el
first()
método Queryset. Devuelve el primer objeto que coincide con el conjunto de consultas, o Ninguno si no hay ningún objeto que coincida.Uso:
fuente
MultipleObjectsReturned()
no se genera, como se documenta aquí . Puede encontrar algunas respuestas mejores aquífirst()
obras exactamente como se supone que debe. Devuelve el primer objeto en el resultado de la consulta y no le importa si se encuentran varios resultados. Si necesita verificar varios objetos devueltos, debe usar.get()
en su lugar..get()
no es adecuado para sus necesidades. La respuesta correcta a esta pregunta se puede encontrar a continuación en @kaapstorm, y es claramente la respuesta más adecuada. Abusar defilter()
esta manera puede llevar a consecuencias inesperadas, algo de lo que OP probablemente no se dio cuenta (a menos que me esté perdiendo algo aquí)MultipleObjectsReturned()
. Si no se espera que el resultado devuelto devuelva varios objetos, no debe tratarse como tal. Hubo un largo debate sobre esto aquíHay dos maneras de hacer esto;
O puede usar una envoltura:
Llámalo así
fuente
queryset
método para hacer esto antes de 1.6! Pero en cuanto a esta construcción, es simplemente torpe. No es "malvado" porque así lo dijo algún autor de tutoriales de tu idioma favorito. Prueba google: "pide perdón en lugar de permiso".get
método no regresaNone
, por lo que una excepción tiene sentido. Se supone que debe usarlo en casos en los que esté seguro de que el objeto estará allí / se "supone" que el objeto está allí. También el uso de excepciones como esta se considera "correcto" porque, bueno, tiene sentido. Quiere unget
contrato con un contrato diferente, por lo que detecta la excepción y la suprime, que es el cambio que busca.Para agregar un código de muestra a la respuesta de Sorki (agregaría esto como un comentario, pero esta es mi primera publicación y no tengo suficiente reputación para dejar comentarios), implementé un administrador personalizado get_or_none así:
Y ahora puedo hacer esto:
fuente
También puede intentar usar django molesto (¡tiene otras funciones útiles!)
instalarlo con:
fuente
Dale a Foo su administrador personalizado . Es bastante fácil: simplemente ponga su código en función en el administrador personalizado, configure el administrador personalizado en su modelo y llámelo con
Foo.objects.your_new_func(...)
.Si necesita una función genérica (para usarla en cualquier modelo, no solo en el administrador personalizado), escriba la suya y colóquela en algún lugar de su ruta de Python e importe, ya no se ensucie.
fuente
Ya sea que lo haga a través de un administrador o una función genérica, es posible que también desee capturar 'MultipleObjectsReturned' en la instrucción TRY, ya que la función get () generará esto si sus kwargs recuperan más de un objeto.
Sobre la base de la función genérica:
y en el administrador:
fuente
Aquí hay una variación de la función auxiliar que le permite pasar opcionalmente una
QuerySet
instancia, en caso de que desee obtener el objeto único (si está presente) de un conjunto de consultas que no sea el conjunto de consultas deall
objetos del modelo (por ejemplo, de un subconjunto de elementos secundarios que pertenecen a un instancia principal):Esto se puede utilizar de dos formas, por ejemplo:
obj = get_unique_or_none(Model, *args, **kwargs)
como se discutió previamenteobj = get_unique_or_none(Model, parent.children, *args, **kwargs)
fuente
Creo que en la mayoría de los casos puedes usar:
Solo si no es crítico que se agregue una nueva entrada en la tabla Foo (otras columnas tendrán los valores Ninguno / predeterminado)
fuente