Skip to main content
 首页 » 编程设计

python之我想缓存 Django 数据库对象而不更改执行数据库查找的每一行

2024年10月01日38unruledboy

简短版本:在 Django(最好是 Django 1.7)中,我只想在每天凌晨 2 点读取某些数据库对象一次并将它们缓存起来。每次我执行 MyModel.objects.get() 时,它都不接触数据库,它会使用缓存。然后我会在凌晨 2 点手动刷新缓存。我不想要更改包含MyModel.objects.get() 等查询的每一行,因为我需要更改 100 多行,而且会变得冗长。

长版:

我正在处理一个非常大的 Django 项目,该项目已经过时且不完全合理。每天一次(在备份后的凌晨 2 点,在计划停机期间),Django 应用程序读取一组 protected 数据库对象(行、模型实例),检查它们的一致性,然后它完全使用那些值直到第二天。这些数据库对象(行)只能在凌晨 2 点的计划停机时间内更改,而在一天中更改它们会损坏数据并使事情变得困惑。

我已经编写了一个 pre_save Hook ,如果您在计划停机时间之外尝试修改这些数据库对象,它会出错。我还允许极少数人通过 Django 管理控制台访问这些数据库表。

但它的性能很低,因为它实际上每次使用这些对象时都会访问数据库,尽管它应该每天只访问一次数据库。

可悲的是,有超过 100 行代码查找然后使用表格,如下所示:

# In views.py: 
from myapp.models import WidgetType 
 
# In literally over 100 places: 
widget_t1 = WidgetType.objects.get(pk=1) 
local_var.part_num = widget_t1.part_num 

每次它说 WidgetType.objects.get 时,我都希望它使用数据库对象的缓存 版本。我只想每天凌晨 2 点手动刷新一次缓存,以提高性能和防止数据损坏的额外安全性。

我不想每次执行数据库查找时都使用缓存模块,因为那样需要更改 100 多行代码,并且会使代码更加冗长。

请您参考如下方法:

django-cacheops为您提供自动缓存的选项。下面是一个示例配置,它自动缓存一些数据库读取并使用 .cache() 为其他人启用手动缓存:

CACHEOPS = { 
    # Automatically cache any User.objects.get() calls for 15 minutes 
    # This includes request.user or post.author access, 
    # where Post.author is a foreign key to auth.User 
    'auth.user': {'ops': 'get', 'timeout': 60*15}, 
 
    # Automatically cache all gets and queryset fetches 
    # to other django.contrib.auth models for an hour 
    'auth.*': {'ops': ('fetch', 'get'), 'timeout': 60*60}, 
 
    # Cache all queries to Permission 
    # 'all' is just an alias for {'get', 'fetch', 'count', 'aggregate', 'exists'} 
    'auth.permission': {'ops': 'all', 'timeout': 60*60}, 
 
    # Enable manual caching on all other models with default timeout of an hour 
    # Use Post.objects.cache().get(...) 
    #  or Tags.objects.filter(...).order_by(...).cache() 
    # to cache particular ORM request. 
    # Invalidation is still automatic 
    '*.*': {'ops': (), 'timeout': 60*60}, 
 
    # And since ops is empty by default you can rewrite last line as: 
    '*.*': {'timeout': 60*60}, 
}