Django: récupérez le premier objet à partir d'une requête de filtrage ou créez
dans Django, queryset fournit une méthode appelée get_or_create qui retourne un objet ou crée un objet.
cependant, comme la méthode get, get_or_create peut jeter une exception si la requête renvoie plusieurs objets.
y a t il une méthode pour ce faire élégamment:
objects = Model.manager.filter(params)
if len(objects) == 0:
obj = Model.objects.create(params)
else:
obj = objects[0]
7 réponses
get_or_create () est juste une fonction de convenance donc il n'y a rien de mal à écrire les vôtres, comme pavid l'a montré ou
result = Model.objects.filter(field__lookup=value)[0]
if not result:
result = Model.objects.create(...)
return result
EDIT Comme suggéré, changé la tranche [:1] (qui renvoie une liste à entrée unique) après le filtre à [0] (qui renvoie l'objet réel). Le problème avec ceci est qu'il va soulever une exception s'il n'y a pas de correspondance à la requête.
cela va également soulever un simliar exception:
Model.objects.filter(field_lookup=value).latest()
en regardant la question à nouveau, Je ne suis pas sûr que l'affiche originale cherche à retourner plusieurs objets/lignes, ou juste un moyen de se déplacer en soulevant une exception lors de la récupération d'un seul objet/ligne.
Voici une autre option?
results = Model.objects.filter(...)
if results.exists():
return results
else:
return Model.objects.create(...)
et un autre:
result = None
try:
result = Model.objects.get(...)
except Model.DoesNotExist:
result = Model.objects.create(...)
il n'y a rien de mal à soulever et à attraper les exceptions!
From django 1.6 il y a une commodité méthode first() qui renvoie le premier résultat dans un filtre de requête, ou Aucun.
obj = Model.manager.filter(params).first()
if obj is None:
obj = Model.objects.create(params)
j'ai juste rencontré cette question et je voulais contribuer parce que personne n'a suggéré réellement attraper L'IndexError.
try:
obj = Model.objects.filter(params)[0]
except IndexError:
obj = Model.objects.create(params)
Voici une méthode de gestionnaire qui vous permettra d'étendre cette fonction avec élégance
class FilterOrCreateManager(models.Manager):
"""Adds filter_or_create method to objects
"""
def filter_or_create(self, **kwargs):
try:
created = False
obj = self.filter(**kwargs).first()
if obj is None:
obj = self.create(**kwargs)
created = True
return (obj,created)
except Exception as e:
print(e)
puis assurez-vous d'ajouter le gestionnaire au(X) Modèle (s) que vous voulez utiliser sur:
class MyObj(models.Model):
objects = FilterOrCreateManager()
après cela, vous pourrez l'utiliser comme vous le feriez get_or_create
:
obj_instance, created = MyObj.filter_or_create(somearg='some value')
Vous pouvez essayer ceci:
result = Model.objects.filter(field__lookup=value)[0]
if not result:
result = Model.objects.create(...)
return result
Cela fonctionne pour moi:
À votre avis, appeler quelque chose comme ceci:
obj = Category.objects.get_or_create_category(form.cleaned_data.get('name'))
dans votre Model manager, créez une fonction comme celle-ci:
class CategoryManager(models.Manager):
def get_or_create_category(self, query):
try:
result = Category.objects.filter(name = query)[0]
except:
result = Category.objects.create(name = query)
return result
La logique est simple. Tout d'abord, essayez de récupérer l'objet de première catégorie dont le nom correspond à la chaîne de requête (qui est fournie par le formulaire). Si la récupération échoue (parce qu'elle n'existe pas), créez une nouvelle catégorie avec la chaîne comme nom. Retourner le résultat pour l'utiliser dans votre vue.
si j'ai bien compris, vous voulez obtenir un objet ou s'il n'existe pas, créer.
donc vous pouvez essayer avec une erreur d'exception mais je ne sais pas qui est le plus efficace:
try:
Model.objects.filter(params)[0]
except Model.IndexError:
Model.objects.create(params)