Django: 何时使用QuerySet none()

41
刚刚在Django文档看到了这个。

调用 none() 将创建一个永远不返回任何对象且在访问结果时不执行任何查询的QuerySet。qs.none() QuerySet 是 EmptyQuerySet 的一个实例。

我构建了很多增删改查应用程序(惊喜),但我想不出什么情况下需要使用 none()
为什么会有人想要返回一个EmptyQuerySet呢?
6个回答

43

通常情况下,如果你需要提供一个QuerySet,但没有可用的 - 例如调用方法或提供给模板。

优点是,如果你知道没有结果(或不想要结果),但你仍然需要一个结果,none()将不会访问数据库。

举个不太现实的例子,假如你有一个API可以查询您的权限。如果帐户尚未确认,由于你已经拥有了Account对象,并且你可以看到account.is_activatedFalse,你可以通过使用Permission.objects.none()跳过检查数据库的权限。


我相信这是正确的,但我要补充一点,似乎一些核心开发者支持移除None()方法。请查看Django支持票号19184 https://code.djangoproject.com/ticket/19184 - David S
1
那里给出的理由都是有效的,但它们批评的是实现而不是模式本身。 - DanielB
1
我不会反对你的观点,只是想补充一下当前功能的观察。 - David S

21
在需要向查询集追加内容但是想要一个空的起点的情况下,可以采用类似于我们实例化一个空列表并逐渐向其中添加有意义的值的条件。例如...
def get_me_queryset(conditionA, conditionB, conditionC):
    queryset = Model.objects.none()

    if conditionA:
        queryset |= some_complex_computation(conditionA)
    elif conditionB:
        queryset |= some_complex_computation(conditionB)

    if conditionC:
        queryset |= some_simple_computation(conditionC)

    return queryset

get_me_queryset 几乎总是应该返回 django.db.models.query.QuerySet 的实例(因为好的编程),而不是 None[],否则它将在以后引入头痛的问题。

这样即使没有一个条件成立,你的代码仍然保持完整。不再需要类型检查。

对于那些不理解此处使用 | 运算符的人:

queryset |= queryset2

它的翻译是:
queryset = queryset + queryset

3

QuerySet.none还有另一个用途,当您不知道是否存在对象但又不想引发错误时使用。

例如:

class DummyMixin(object):

    def get_context_data(self,**kwargs):
        """ Return all the pks of objects into the context """

        context = super(DummyMixin, self).get_context_data(**kwargs)

        objects_pks = context.get(
            "object_list",
            Mymodel.objects.none()
        ).values_list("pk", flat=True)

        context["objects_pks"] = objects_pks

2
另一个很好的用例是,如果某个调用方法想要在结果上调用 .values_list()或类似方法。如果该方法返回None,则会出现如下错误:

AttributeError:'list' object has no attribute 'values_list'

但是,如果你的子句返回 MyModel.objects.none()而不是 None,则调用代码将很高兴,因为返回的数据是一个空查询集而不是None对象。

换句话说,它允许您不混合返回类型(例如“此函数返回QuerySet或None”,这很麻烦)。

最初的回答


1

在Django文档的其他示例中看到qs.none()的用法是有益的,特别是当使用查询集初始化模型表单集时,如果您希望结果为空,则给出的示例如下:

formset = AuthorFormSet(queryset=Author.objects.none())


0

none()用于get_queryset(),根据has_view_or_change_permission()的状态返回空查询集,如下所示:

class BaseModelAdmin(metaclass=forms.MediaDefiningClass):

    # ...

    def has_view_or_change_permission(self, request, obj=None):
        return self.has_view_permission(request, obj) or self.has_change_permission(
            request, obj
        )

# ...

class InlineModelAdmin(BaseModelAdmin):

    # ...

    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        if not self.has_view_or_change_permission(request):
            queryset = queryset.none() # Here
        return queryset

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接