Existe-t-il une fonction Django qui me permettra d'obtenir un objet de la base de données, ou None si rien ne correspond?
En ce moment, j'utilise quelque chose comme:
foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None
Mais ce n'est pas très clair et c'est compliqué d'en avoir partout.
len(foo)
c'est mauvais : " Remarque: n'utilisez pas len () sur les QuerySets si tout ce que vous voulez faire est de déterminer le nombre d'enregistrements dans l'ensemble. Il est beaucoup plus efficace de gérer un décompte au niveau de la base de données, en utilisant SELECT COUNT de SQL (), et Django fournit une méthode count () précisément pour cette raison. ". Réécrit:foo = foo[0] if foo.exists() else None
first()
: PRéponses:
Dans Django 1.6, vous pouvez utiliser la
first()
méthode Queryset. Il renvoie le premier objet correspondant à l'ensemble de requêtes, ou None s'il n'y a pas d'objet correspondant.Usage:
la source
MultipleObjectsReturned()
n'est pas déclenché, comme documenté ici . Vous pouvez trouver de meilleures réponses icifirst()
fonctionne exactement comme il le suppose. Il renvoie le premier objet dans le résultat de la requête et ne se soucie pas si plusieurs résultats sont trouvés. Si vous avez besoin de vérifier plusieurs objets renvoyés, utilisez.get()
plutôt..get()
ne convient pas à ses besoins. La réponse correcte à cette question peut être trouvée ci-dessous par @kaapstorm, et est clairement la réponse la plus appropriée. Abuser defilter()
cette façon peut entraîner des conséquences inattendues, ce que OP n'a probablement pas réalisé (sauf si je manque quelque chose ici)MultipleObjectsReturned()
. Si le résultat renvoyé ne doit pas renvoyer plusieurs objets, il ne doit pas être traité comme tel. Il y a eu un long débat à ce sujet iciIl y a deux façons de faire ça;
Ou vous pouvez utiliser un wrapper:
Appelez ça comme ça
la source
queryset
méthode pour le faire avant la 1.6! Mais quant à cette construction, elle est tout simplement maladroite. Ce n'est pas "mal" parce qu'un auteur de tutoriel de votre langue préférée l'a dit. Essayez google: "demandez pardon plutôt que par permission".get
méthode n'est pas censée retournerNone
, donc une exception a du sens. Vous êtes censé l'utiliser dans les cas où vous êtes sûr que l'objet sera là / l'objet est "supposé" y être. Utiliser également des exceptions comme celle-ci est considéré comme «correct» car, eh bien, cela a du sens. Vous voulez unget
avec un contrat différent, donc vous attrapez l'exception et la supprimez, ce qui est le changement que vous recherchez.Pour ajouter un exemple de code à la réponse de sorki (j'ajouterais ceci en commentaire, mais c'est mon premier article, et je n'ai pas assez de réputation pour laisser des commentaires), j'ai implémenté un gestionnaire personnalisé get_or_none comme ceci:
Et maintenant je peux faire ceci:
la source
Vous pouvez également essayer d'utiliser django ennuyeux (il a une autre fonction utile!)
installez-le avec:
la source
Donnez à Foo son gestionnaire personnalisé . C'est assez simple: mettez simplement votre code en fonction dans le gestionnaire personnalisé, définissez le gestionnaire personnalisé dans votre modèle et appelez-le avec
Foo.objects.your_new_func(...)
.Si vous avez besoin d'une fonction générique (pour l'utiliser sur n'importe quel modèle, pas seulement avec un gestionnaire personnalisé), écrivez la vôtre et placez-la quelque part sur votre chemin python et importez-la, pas plus compliquée.
la source
Que ce soit via un gestionnaire ou une fonction générique, vous voudrez peut-être aussi attraper 'MultipleObjectsReturned' dans l'instruction TRY, car la fonction get () lèvera cela si vos kwargs récupèrent plus d'un objet.
S'appuyant sur la fonction générique:
et dans le gestionnaire:
la source
Voici une variante de la fonction d'assistance qui vous permet de passer éventuellement une
QuerySet
instance, au cas où vous voudriez obtenir l'objet unique (le cas échéant) à partir d'un ensemble de requêtes autre que l'ensemble deall
requêtes d'objets du modèle (par exemple, à partir d'un sous-ensemble d'éléments enfants appartenant à un instance parent):Cela peut être utilisé de deux manières, par exemple:
obj = get_unique_or_none(Model, *args, **kwargs)
comme discuté précédemmentobj = get_unique_or_none(Model, parent.children, *args, **kwargs)
la source
Je pense que dans la plupart des cas, vous pouvez simplement utiliser:
Seulement s'il n'est pas critique qu'une nouvelle entrée soit ajoutée dans la table Foo (les autres colonnes auront les valeurs None / par défaut)
la source