我正在调用一个函数来启动一个需要更长时间才能执行的进程,完成了很多不同的事情。此函数主要处理特定类Item
的实例。这些项目按不同属性进行分类:category1
,category2
和category3
。
现在,有一种不同的模型可以对这些类别应用某种规则:Rule
具有多对多属性:categories1
,categories2
和categories3
。规则适用于Item
,如果相同的规则指向不同的类别,则只应应用其中一个。决定哪一个由封装在函数中的某个逻辑定义:
class Rule(models.Model):
warehouse = models.ForeignKey('Warehouse')
categories1 = models.ManyToManyField('Category1')
categories2 = models.ManyToManyField('Category2')
categories3 = models.ManyToManyField('Category3')
@staticmethod
def get_rules_that_applies(item):
rules = warehouse.rule_set.all()
if not rules.exists():
return None
# ... determine which rule applies to the item by filtering, etc.
return rule
问题在于get_rules_that_applies
方法。每当我们需要获得适用于某个项目的规则时,让我再说一遍,我们正在讨论的过程涉及很多项目,warehouse.rule_set.all()
被调用。
由于规则在此过程中不会更改,我们可以只缓存仓库中的所有规则,但如何?如何确保缓存warehouse = warehouse.rule_set.all()
并且对这些规则起作用的所有过滤和QuerySet操作都没有到达数据库?
答案 0 :(得分:0)
你有两个选择:
代码在视图和模型中是相同的,导入cahce:
from django.core.cache import cache
代码:
if cache.get('query_result') is not None:
return cache.get('query_result')
else:
cache.set('query_result', result, 3600)
#cache.set('cache_name', 'your query', 'expiry time')
return rule
您的模型将是:
class Rule(models.Model):
warehouse = models.ForeignKey('Warehouse')
categories1 = models.ManyToManyField('Category1')
categories2 = models.ManyToManyField('Category2')
categories3 = models.ManyToManyField('Category3')
@staticmethod
def get_rules_that_applies(item):
rules = warehouse.rule_set.all()
if not rules.exists():
return None
# ... determine which rule applies to the item by filtering, etc.
if cache.get('query_result') is not None:
return cache.get('query_result')
else:
cache.set('query_result', result, 3600)
#cache.set('cache_name', 'your query', 'expiry time')
return rule
return rule
关于Django查询的几个信息,当它们被评估时?:
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#when-querysets-are-evaluated
希望这个帮助
答案 1 :(得分:0)
我相信您所寻求的解决方案是get_rules_that_applies
方法的memoization。
有一个现成的工具,名为django-memoize
,those是其文档。
快速使用:
pip install django-memoize
将其放在INSTALLED_APPS
INSTALLED_APPS = [
'...',
'memoize',
]
在model.py
:
from memoize import memoize
class Rule(models.Model):
warehouse = models.ForeignKey('Warehouse')
categories1 = models.ManyToManyField('Category1')
categories2 = models.ManyToManyField('Category2')
categories3 = models.ManyToManyField('Category3')
@staticmethod
@memoize(timeout=something_reasonable_in_seconds)
def get_rules_that_applies(item):
rules = warehouse.rule_set.all()
if not rules.exists():
return None
# ... determine which rule applies to the item by filtering, etc.
return rules
(更新)半DIY方法:
自从我的回答以来,我读了以下帖子:https://www.peterbe.com/plog/cache_memoize-cache-decorator-for-django,其中附有关于如何自己实现备忘的gist。
更多DIY方法:
Python 3.2及以上版本:
@functools.lru_cache
装饰器是:
Decorator用一个memoizing callable来包装一个函数,该函数可以保存maxsize最近的调用。当使用相同的参数定期调用昂贵的或I / O绑定函数时,它可以节省时间。
如何使用它:
from functools import lru_cache
class Rule(models.Model):
...
@lru_cache(maxsize=a_reasonable_integer_size_of_cache)
def get_rules_that_applies(item):
rules = warehouse.rule_set.all()
if not rules.exists():
return None
# ... determine which rule applies to the item by filtering, etc.
return rules
maxsize
:定义要存储的函数调用中的缓存大小。可以将其设置为None
以缓存每个呼叫。
Python< 3.2 强>
在这里What is memoization and how can I use it in Python?存在更“老派”的方法。
如何使用上述任一方法缓存查询集:
为什么不定义一个中间函数来形成用于结果的查询集和缓存?
@lru_cache(maxsize=None)
or
@memoize()
def middle_function():
return warehouse.rule_set.all()
然后在您的get_rules_that_applies
函数中:
def get_rules_that_applies(item):
rules = middle_function()