python - template - Django: Obtiene un objeto del DB o ''Ninguno'' si nada coincide
import django template (8)
¿Hay alguna función de Django que me permita obtener un objeto de la base de datos, o None si no coincide nada?
En este momento 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.
Aquí hay una variación de la función auxiliar que le permite pasar opcionalmente una instancia de QuerySet
, en caso de que desee obtener el objeto único (si está presente) de un conjunto de consulta que no sea el all
objetos de all
objetos del modelo (por ejemplo, desde un subconjunto de elementos secundarios a una instancia principal):
def get_unique_or_none(model, queryset=None, *args, **kwargs):
"""
Performs the query on the specified `queryset`
(defaulting to the `all` queryset of the `model`''s default manager)
and returns the unique object matching the given
keyword arguments. Returns `None` if no match is found.
Throws a `model.MultipleObjectsReturned` exception
if more than one match is found.
"""
if queryset is None:
queryset = model.objects.all()
try:
return queryset.get(*args, **kwargs)
except model.DoesNotExist:
return None
Esto se puede usar de dos maneras, por ejemplo:
-
obj = get_unique_or_none(Model, *args, **kwargs)
como se discutió previamente -
obj = get_unique_or_none(Model, parent.children, *args, **kwargs)
Creo que en la mayoría de los casos puedes usar:
foo, created = Foo.objects.get_or_create(bar=baz)
Solo si no es crítico que se agregue una nueva entrada en la tabla Foo (otras columnas tendrán los valores Ninguno / predeterminado)
Dale a Foo su administrador personalizado . Es bastante fácil: simplemente ponga su código en funcionamiento en el administrador personalizado, configure el administrador personalizado en su modelo y Foo.objects.your_new_func(...)
con Foo.objects.your_new_func(...)
.
Si necesita una función genérica (para usarla en cualquier modelo y no solo con un administrador personalizado), escriba la suya y colóquela en algún lugar de su ruta python para importarla, sin crear problemas.
En Django 1.6 puedes usar el first()
método de Queryset. Devuelve el primer objeto que coincide con el conjunto de consulta, o Ninguno si no hay ningún objeto coincidente.
Uso:
p = Article.objects.order_by(''title'', ''pub_date'').first()
Hay dos maneras de hacer esto;
try:
foo = Foo.objects.get(bar=baz)
except model.DoesNotExist:
foo = None
O puede usar un contenedor:
def get_or_none(model, *args, **kwargs):
try:
return model.objects.get(*args, **kwargs)
except model.DoesNotExist:
return None
Llámalo así
foo = get_or_none(Foo, baz=bar)
Para agregar un código de muestra a la respuesta de Sorki (lo agregaría como un comentario, pero esta es mi primera publicación, y no tengo suficiente reputación para dejar comentarios), implementé un gestor personalizado get_or_none así:
from django.db import models
class GetOrNoneManager(models.Manager):
"""Adds get_or_none method to objects
"""
def get_or_none(self, **kwargs):
try:
return self.get(**kwargs)
except self.model.DoesNotExist:
return None
class Person(models.Model):
name = models.CharField(max_length=255)
objects = GetOrNoneManager()
Y ahora puedo hacer esto:
bob_or_none = Person.objects.get_or_none(name=''Bob'')
También puedes intentar usar django molesto (¡tiene otras funciones útiles!)
instalarlo con:
pip install django-annoying
from annoying.functions import get_object_or_None
get_object_or_None(Foo, bar=baz)
Ya sea que lo haga a través de un administrador o una función genérica, también puede querer atrapar ''MultipleObjectsReturned'' en la declaración TRY, ya que la función get () lo planteará si sus kwargs recuperan más de un objeto.
Construyendo sobre la función genérica:
def get_unique_or_none(model, *args, **kwargs):
try:
return model.objects.get(*args, **kwargs)
except (model.DoesNotExist, model.MultipleObjectsReturned), err:
return None
y en el gerente:
class GetUniqueOrNoneManager(models.Manager):
"""Adds get_unique_or_none method to objects
"""
def get_unique_or_none(self, *args, **kwargs):
try:
return self.get(*args, **kwargs)
except (self.model.DoesNotExist, self.model.MultipleObjectsReturned), err:
return None