覆盖 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" 行为,你应该这样写你的方法。
有人可以解释为什么覆盖 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" 行为,你应该这样写你的方法。