不偷懒 Queryset 调用外部方法

Not lazy Queryset calls outside methods

我在工作中使用 Django,我仍在学习它的一些功能 - 最近我 运行 在我的一个视图中遇到了 Queryset 调用的问题。虽然代码 运行 非常适合我,但它在 CI 管道集上中断以从头开始初始化项目。

我得到的答案是因为对上述调用进行了非惰性评估——准确地说,它大致如下所示:

class MyListView(ListView):
    queryset = (
        MyModel.objects.all()
        .exclude(some_type_field__in=[ContentType.objects.get_for_model(MyReferenceModel)])
        .distinct()
    )
    
    template_name = #...

此外,我被告知不要编写未在方法之外延迟评估的 Queryset 调用 - 原因是 Python 解释器逐个模块执行代码。

但是我不明白这部分。方法与它有什么关系?如果上面的代码尝试实际访问数据库,为什么会出现问题?

为了进一步说明我的问题,我展示了我得到的解决方案:

class MyListView(ListView):
    model = MyModel

    def get_queryset(self):
        return (
            super()
                .get_queryset()
                .exclude(some_type_field__in=[ContentType.objects.get_for_model(MyReferenceModel)])
                .distinct()
        )

    template_name =  # ...

两者之间的实际区别是什么?我需要更好地理解这个问题,而 Django wiki 没有帮助。

不同之处在于,当您从此模块导入任何内容时,将执行模块和 class 级别的代码。

这就是 python 导入系统的工作方式,python 只是运行 .py 文件中的所有内容并将其放入全局模块“缓存”。

另一方面,除非调用,否则函数不会执行。唯一执行的是函数定义签名。即

def f(arg=[][0]):
    return 1/0

导入时会给你 IndexError

你可以通过写文件来检查这个

# my_module.py
x = 4
print(x)

class A:
    y = input("Hey, I'm blocking!")

    def method(self):
        return input("Hey, I'm not blocking unless called!")

然后从您的代码中尝试 from my_module import A

如果您在具有任何 i/o 的环境中工作 – 带有数据库的 Web 框架 – 这是常见的做法,在 import 中没有任何 i/o时间。通常,有一些机器可以帮助您解决这个问题。例如,在 django 中是 AppConfig hooks.