Как исключить результаты с get_object_or_404? - PullRequest
13 голосов
/ 15 июня 2010

В Django вы можете использовать исключение для создания SQL, похожего на not equal. Примером может быть.

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

Теперь это прекрасно работает, а исключение очень гибкое. Поскольку я немного ленив, я хотел бы получить эту функциональность при использовании get_object_or_404, но я не нашел способа сделать это, так как вы не можете использовать исключение на get_object_or_404.

Я хочу сделать что-то вроде этого:

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

Но, к сожалению, это не работает, поскольку нет фильтра исключающих запросов или чего-либо подобного. Лучшее, что я придумала до сих пор, это что-то вроде этого:

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

Выполнение чего-то подобного действительно лишает смысла использование get_object_or_404, так как оно больше не является удобным однострочником.

В качестве альтернативы я мог бы сделать:

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

Но это было бы не очень легко обслуживать, так как мне нужно было бы обновлять список.

Интересно, мне не хватает какой-то хитрости или функции в django, чтобы использовать get_object_or_404 для получения желаемого результата?

Ответы [ 4 ]

16 голосов
/ 15 июня 2010

Использование django.db.models.Q:

from django.db.models import Q

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

Объекты Q позволяют вам НЕ (с оператором ~) и ИЛИ (с оператором |) в дополнение к AND.

Обратите внимание, что объект Q должен предшествовать pk=id, потому что ключевые аргументы должны быть последними в Python.

6 голосов
/ 22 августа 2016

Наиболее распространенный вариант использования - передать модель.Однако вы также можете передать экземпляр QuerySet:

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

Пример документации Django: https://docs.djangoproject.com/en/1.10/topics/http/shortcuts/#id2

1 голос
/ 12 января 2016

Есть другой способ вместо использования объектов Q.Вместо того, чтобы передавать модель в get_object_or_404, просто передайте QuerySet в функцию вместо:

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

Однако одним из побочных эффектов является повышение MultipleObjectsReturnedисключение, если QuerySet возвращает несколько результатов.

0 голосов
/ 24 августа 2017

get_object_or_404 использует метод get_queryset менеджера объектов.Если вы переопределите метод get_queryset, чтобы возвращать только те элементы, которые не были «удалены», то get_object_or_404 будет автоматически вести себя так, как вы хотите.Тем не менее, переопределение get_queryset, как это, вероятно, будет иметь проблемы в других местах (возможно, на страницах администратора), но вы можете добавить альтернативный менеджер для доступа к программно удаленным элементам.

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

Так что есливам нужны только не удаленные элементы, которые вы можете сделать get_object_or_404(Models, id=id), но если вам нужны все элементы, вы можете сделать get_object_or_404(Models.all_objects, id=id).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...