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]
20
demandé sur arustgi 2011-05-31 20:42:48

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!

29
répondu Timmy O'Mahony 2011-08-29 19:28:52

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)
17
répondu Sean 2015-07-15 07:43:21

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)
4
répondu demux 2013-04-23 11:35:27

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')
4
répondu Duncan 2016-02-19 17:31:23

Vous pouvez essayer ceci:

result = Model.objects.filter(field__lookup=value)[0]
if not result:
   result = Model.objects.create(...)
return result
1
répondu Afsa Ahmed 2017-08-02 18:24:58

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.

0
répondu bento 2012-05-11 00:39:30

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)    
-1
répondu psoares 2017-06-14 17:32:05