我一直在苦苦挣扎数小时:我无法找到一种正确的方法来缓存对象查询集结果( object = queryset.get())以避免重新使用 - 在每个视图请求上访问数据库。
这是我当前的(简化)代码,正如您所看到的,我重写了get_object()以添加一些额外的数据(不仅是今天的变量),检查对象是否在会话中并将对象添加到会话。
views.py
from myapp import MyModel
from django.core.cache.utils import make_template_fragment_key
from django.views.generic import DetailView
class myClassView(DetailView):
model = MyModel
def get_object(self,queryset=None):
if queryset is None:
queryset = self.get_queryset()
pk = self.kwargs.get(self.pk_url_kwarg, None)
if pk is not None:
queryset = queryset.filter(pk=pk)
else:
raise AttributeError("My error message.")
try:
today = datetime.today().strftime('%Y%m%d')
cache_key = make_template_fragment_key('some_name', [pk, today])
if cache.has_key(cache_key):
object = self.request.session[cache_key]
return object
else:
object = queryset.get()
object.id = my_id
object.today = today
# Add object to session
self.request.session[cache_key] = object
except queryset.model.DoesNotExist:
raise Http404("Error 404")
return object
以上只有在我添加以下内容时才有效:
settings.py
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
但是我不喜欢这个黑客,因为对于Django 1.6和更新的版本来说它并不安全,因为根据How To Use Sessions (Django 1.7 documents):
如果SECRET_KEY没有保密并且你正在使用PickleSerializer,这可能导致任意远程代码执行
如果我没有添加SESSIONS_SERIALIZER行,我会得到一个" django object is not JSON serializable"错误。但是,在其他地方,我的代码中断了,并且在尝试从会话中提取数据时出现KeyError错误。解决了这个问题,将我的字符串键转换为整数。在更改设置文件之前,当请求会话数据时,Django会自动将str键转换为整数。
因此,考虑到此会话序列化程序安全问题,我更喜欢其他选项。所以我阅读了here和here关于缓存get_object()的内容,但我还是不知道如何将其纳入我的get_object()位。我试过..
if cache.has_key(cache_key):
self._object = super(myClassView,self).get_object(queryset=None)
return self._object
......但它失败了。这似乎是迄今为止最好的解决方案。但是我如何在我的代码中实现它?或者,有更好的主意吗?我全都耳朵。谢谢!
答案 0 :(得分:1)
您应该退后一步并重新评估情况。你想要实现什么目标? get_object是在详细视图中调用的方法,用于从数据库访问一个特定对象。 如果在第一次对象在Queryset中失效并缓存时访问此方法。 为了缓存get_queryset方法,您需要一个良好的缓存后端,如Redis或Memcached,以便您可以执行简单的直写缓存操作:
if cache.has_key(cache_key):
object = cache.get(cache_key)
return object
else:
object = queryset.get(pk=pk)
cache.set(cache_key,object)
return object
请注意,django对象在缓存后端中序列化,并在反序列化时作为对象检索。 这种方法只是一个起点。您在第一次未命中时缓存该对象。 您还可以添加post_save,post_update信号,以便在每次保存或更新模型时将对象保存在缓存中:
@receiver(post_save, sender=MyModel)
@receiver(post_delete, sender=MyModel)
def add_MyModel_to_cache(sender, **kwargs):
object = kwargs['instance']
cache.set(cache_key,object)
您必须仔细检查要缓存的内容以及何时容易误判请求