代码之家  ›  专栏  ›  技术社区  ›  dabadaba

确保缓存queryset

  •  1
  • dabadaba  · 技术社区  · 9 年前

    我调用了一个函数,它启动了一个执行时间更长的进程,完成了许多不同的事情。此函数主要处理特定类的实例, Item category1 , category2 category3 .

    现在,有一个不同的模型将某种规则应用于这些类别: Rule 具有多对多属性: categories1 , categories2 categories3 项目

    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() 是否缓存了,并且所有根据这些规则进行的过滤和查询集操作都没有命中数据库?

    2 回复  |  直到 8 年前
        1
  •  1
  •   John Moutafis Milani Igor    8 年前

    我相信你正在寻求的解决方案是 memoization get_rules_that_applies 方法

    有一种现成的工具,叫做 django-memoize those 是它的文档。

    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
      

    从我的回答开始,我读了以下帖子: https://www.peterbe.com/plog/cache_memoize-cache-decorator-for-django gist 关于如何实现自我记忆。


    Python 3.2及更高版本:

    @functools.lru_cache 装饰师是:

    Decorator将函数包装为一个可记忆的可调用函数,该函数最多可保存最大大小的最近调用。当使用相同的参数定期调用昂贵的函数或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()
    

    然后在你的 功能:

    def get_rules_that_applies(item):
        rules = middle_function()
    
        2
  •  0
  •   Mattia    9 年前

    您有2种选择:

    1. 在视图中缓存项目
    2. 计算模型中的项目

    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
    

    https://docs.djangoproject.com/en/1.11/ref/models/querysets/#when-querysets-are-evaluated

    希望这有帮助