2010-06-15 17 views
13

En Django puede usar la exclusión para crear SQL similar a not equal. Un ejemplo podría ser.¿Cómo excluir resultados con get_object_or_404?

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

Ahora esto funciona muy bien y excluir es muy flexible. Como soy un poco flojo, me gustaría obtener esa funcionalidad cuando utilizo get_object_or_404, pero no he encontrado una manera de hacerlo, ya que no puede usar exclude en get_object_or_404.

Lo que yo quiero es hacer algo como esto:

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

Pero lamentablemente esto no funciona, ya que no es un filtro de consulta excluir o similar. El mejor que he encontrado hasta el momento está haciendo algo como esto:

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

Hacer algo así, realmente se pierde el punto de utilizar get_object_or_404, puesto que ya no es un práctico de una sola línea.

alternativa que podía hacer:

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

Pero eso no sería muy fácil de mantener, ya que tendría que mantener la lista actualizada.

Me pregunto si me falta algún truco o función en django para usar get_object_or_404 para obtener el resultado deseado?

+0

No es realmente una respuesta, pero parece que en realidad no desea 404 para un objeto eliminado. El objetivo de la eliminación suave es mantener el objeto "por las dudas". –

Respuesta

17

Uso django.db.models.Q:

from django.db.models import Q 

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

Los objetos Q le permite hacer NO (con ~ operador) y OR (con | operador), además de Y.

Tenga en cuenta que el objeto Q debe venir antes que pk=id, porque los argumentos de la palabra clave deben ser los últimos en Python.

+0

De causa del objeto Q. No sabía que funcionaría en ese concurso. Gracias. – googletorp

+1

Aparte de un modelo, también puede pasar un Manager o un QuerySet como primer parámetro. Ver http://stackoverflow.com/a/26476339/336694 – Heliodor

1

Hay otra manera en lugar de utilizar objetos Q. En lugar de pasar el modelo a get_object_or_404 sólo tiene que pasar el QuerySet a la función en su lugar:

efecto

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

Un lado de esta, sin embargo, es que provocará una excepción MultipleObjectsReturned si el QuerySet devuelve varios resultados.

6

El caso de uso más común es pasar un modelo. Sin embargo, también puede pasar una instancia de QuerySet:

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

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

+0

Creo que esta es una solución más fácil de seguir que la respuesta aceptada. Quiero decir, si estoy revisando mi código de hace 6 meses, me gustaría golpearme en la cara si utilizo un objeto Q en lugar de filtrar con una exclusión. –

0

get_object_or_404 utiliza el método del administrador de objetos get_queryset. Si anula el método get_queryset para que solo devuelva elementos que no son "eliminados", entonces get_object_or_404 se comportará automáticamente como lo desee. Sin embargo, anular get_queryset de esta manera probablemente tenga problemas en otros lugares (quizás en las páginas de administración), pero podría agregar un administrador alternativo para cuando necesite acceder a los elementos eliminados.

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() 

lo que si necesita sólo los elementos no-borrado que puede hacer get_object_or_404(Models, id=id) pero si usted necesita todos los elementos que pueden hacer get_object_or_404(Models.all_objects, id=id).

Cuestiones relacionadas