2010-06-15 4 views
13

Dans Django, vous pouvez utiliser l'exclure pour créer un code SQL similaire à not equal. Un exemple pourrait être.Comment exclure les résultats avec get_object_or_404?

Model.objects.exclude(status='deleted') 

Maintenant, cela fonctionne très bien et l'exclusion est très flexible. Depuis que je suis un peu paresseux, je voudrais obtenir cette fonctionnalité lors de l'utilisation get_object_or_404, mais je n'ai pas trouvé un moyen de le faire, car vous ne pouvez pas utiliser exclure sur get_object_or_404.

Ce que je veux est de faire quelque chose comme ceci:

model = get_object_or_404(pk=id, status__exclude='deleted') 

Mais malheureusement cela ne fonctionne pas car il n'y a pas d'exclure le filtre de requête ou similaire. Le meilleur que je suis venu avec à ce jour fait quelque chose comme ceci:

object = get_object_or_404(pk=id) 
if object.status == 'deleted': 
    return HttpResponseNotfound('text') 

Faire quelque chose comme ça, défaites vraiment le point d'utiliser get_object_or_404, car il n'est en une ligne à portée de main.

Sinon je pouvais faire:

object = get_object_or_404(pk=id, status__in=['list', 'of', 'items']) 

Mais ce ne serait pas très maintenable, comme je l'aurais besoin de garder la liste à jour.

Je me demande si je manque un truc ou une fonctionnalité dans django pour utiliser get_object_or_404 pour obtenir le résultat souhaité?

+0

Ce n'est pas vraiment une réponse, mais il semble que vous ne voudriez pas vraiment 404 pour un objet supprimé. Le point entier de la suppression douce est de garder l'objet autour "juste au cas où". –

Répondre

17

Utilisation django.db.models.Q:

from django.db.models import Q 

model = get_object_or_404(MyModel, ~Q(status='deleted'), pk=id) 

Les objets Q vous permet de faire pas (avec l'opérateur ~) et OR (avec | opérateur), en plus de ET.

Notez que l'objet Q doit précéder pk=id, car les arguments de mot-clé doivent venir en dernier dans Python.

+0

De cause l'objet Q. Je ne savais pas que cela fonctionnerait dans ce concours. Merci. – googletorp

+1

Outre un modèle, vous pouvez également passer un gestionnaire ou un QuerySet en tant que premier paramètre. Voir http://stackoverflow.com/a/26476339/336694 – Heliodor

1

Il existe une autre façon d'utiliser les objets Q. Au lieu de passer le modèle à get_object_or_404 juste passer le QuerySet à la fonction à la place:

model = get_object_or_404(MyModel.objects.filter(pk=id).exclude(status='deleted'))

Un effet secondaire de cela, cependant, est qu'il déclenche une exception MultipleObjectsReturned si le QuerySet renvoie plusieurs résultats.

6

Le cas d'utilisation le plus courant consiste à passer un modèle. Cependant, vous pouvez également passer une instance QuerySet:

queryset = Model.objects.exclude(status='deleted') 
get_object_or_404(queryset, pk=1) 

Django docs exemple: https://docs.djangoproject.com/en/1.10/topics/http/shortcuts/#id2

+0

Je pense que c'est une solution plus facile à suivre que la réponse acceptée. Je veux dire que si je regarde mon code d'il y a 6 mois, je voudrais me pointer au visage si j'utilise un objet Q au lieu de filtrer avec un exclu. –

0

get_object_or_404 utilise la méthode get_queryset du gestionnaire d'objets. Si vous remplacez la méthode get_queryset pour renvoyer uniquement les éléments qui ne sont pas "supprimés", get_object_or_404 se comportera automatiquement comme vous le souhaitez. Toutefois, en remplaçant get_queryset comme ceci aura probablement des problèmes ailleurs (peut-être dans les pages d'administration), mais vous pourriez ajouter un gestionnaire alternatif pour quand vous devez accéder aux éléments doux supprimés.

from django.db import models 

class ModelManger(models.Manger): 
    def get_queryset(self): 
     return super(ModelManger, self).get_queryset().exclude(status='deleted') 

class Model(models.Model): 
    # ... model properties here ... 

    objects = ModelManager() 
    all_objects = models.Manager() 

Donc, si vous avez besoin que des éléments non supprimés que vous pouvez faire get_object_or_404(Models, id=id) mais si vous avez besoin tous les éléments que vous pouvez faire get_object_or_404(Models.all_objects, id=id).

Questions connexes