覆盖 get_queryset 会导致 ListView 中的缓存问题,其中数据仍然陈旧

Overriding get_queryset leads to caching headache in ListView, where data remains stale

有人可以解释为什么覆盖 get_queryset 并通过 self 引用查询集会完全缓存页面吗?我需要等待 5 分钟或更长时间才能显示对数据库的更新。

我正在尝试为每个对象保存一个临时值并将其传递给模板。

在示例 3 中,我的一切都运行良好,但我并不真正理解我做了什么让它运行,所以任何见解都会很棒!

示例 1:缓存几分钟,但 r.css='abc' 工作正常

class AppointmentListView(ListView):
    qs = Appointment.objects.prefetch_related('client', 'patients')

    def get_queryset(self):
        for r in self.qs:
            r.css = 'abc' #<-passes temp value to template ok
        return self.qs

示例 2:没有缓存问题,但 r.css='abc' 现在不起作用

如果我不包含方法而只是自动调用查询集,则不会立即显示缓存和数据库更新,但我的临时数据不会到达模板。 class 约会列表视图(列表视图):

    queryset = Appointment.objects.prefetch_related('client','patients')

    for r in queryset:
        r.css = 'abc' #<- NOT passed to template

示例 3:没有缓存问题并且 r.css='abc' 工作正常

最后,如果我将所有内容都放入方法中,一切正常 - 临时数据到达模板并且没有缓存。

class AppointmentListView(ListView):

    def get_queryset(self):
        qs = Appointment.objects.prefetch_related('client','patients')
        for r in qs:
            r.css = 'abc' #<-passes to template ok

        return qs

您看到的行为就是 Python 评估您的代码的方式。下面是一个简化的示例,可以解释您所看到的内容。

import random

class Example1(object):
    roll = random.randint(1, 6) # this is evaluated immediately!
    def get_roll(self):
        return self.roll

ex1 = Example1()

# the call below always returns the same number! 
# (until Python re-interprets the class)
ex1.get_roll() 

如果将上面的代码输入 python 解释器,您会注意到 ex1.get_roll() 总是 returns 相同的数字!

Example1.roll 被称为 class 或静态变量。当 class 被定义时,这些只被评估一次。

class Example2(object):
    def get_number(self):
        roll = random.randint(1,6)
        return roll

Example2中,每次调用get_roll方法都会生成一个新的随机数。

对于您问题中列出的示例:

示例 1

qs 是一个 class 变量,因此只计算一次(这就是为什么你会看到 "caching" 行为)。随后调用 get_queryset returns 与最初评估的相同 qs 变量。

示例 2

您没有覆盖 get_queryset,这意味着使用了 ListView.get_queryset 实现。

Django 的 ListView.get_queryset 在计算之前复制 queryset - 这就是为什么你看不到 "caching" 的原因。但是,由于复制了查询集,因此 for 循环的效果被丢弃了。

示例 3

这通常是编写代码的正确方法。如果你不想看到 "caching" 行为,你应该这样写你的方法。