在Django中,您可以使用exclude来创建类似于not equal
的SQL。一个例子可能是。
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
来获得所需的结果?
答案 0 :(得分:16)
from django.db.models import Q
model = get_object_or_404(MyModel, ~Q(status='deleted'), pk=id)
除了AND之外,Q对象不允许(使用~
运算符)和OR(使用|
运算符)。
请注意,Q对象必须在pk=id
之前,因为关键字参数必须在Python中排在最后。
答案 1 :(得分:6)
最常见的用例是传递模型。但是,您也可以传递QuerySet实例:
queryset = Model.objects.exclude(status='deleted')
get_object_or_404(queryset, pk=1)
Django docs示例: https://docs.djangoproject.com/en/1.10/topics/http/shortcuts/#id2
答案 2 :(得分:1)
还有另一种方法,而不是使用Q对象。而不是将模型传递给get_object_or_404
而只是将QuerySet传递给函数:
model = get_object_or_404(MyModel.objects.filter(pk=id).exclude(status='deleted'))
然而,这样做的一个副作用是,如果QuerySet返回多个结果,它将引发MultipleObjectsReturned
异常。
答案 3 :(得分:0)
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)
。