确保缓存查询集

时间:2017-08-10 09:16:37

标签: python django caching

我正在调用一个函数来启动一个需要更长时间才能执行的进程,完成了很多不同的事情。此函数主要处理特定类Item的实例。这些项目按不同属性进行分类:category1category2category3

现在,有一种不同的模型可以对这些类别应用某种规则:Rule具有多对多属性:categories1categories2categories3 。规则适用于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操作都没有到达数据库?

2 个答案:

答案 0 :(得分:0)

你有两个选择:

  1. 在视图中缓存项目
  2. 了解模型中的项目
  3. 代码在视图和模型中是相同的,导入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-memoizethose是其文档。

快速使用:

  1. pip install django-memoize
  2. 将其放在INSTALLED_APPS

    INSTALLED_APPS = [
        '...',
        'memoize',
    ]
    
  3. 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
    
  4. (更新)半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()