【问题标题】:How to cache Django Rest Framework API calls?如何缓存 Django Rest Framework API 调用?
【发布时间】:2016-11-14 04:07:29
【问题描述】:

我使用 Memcached 作为我的 django 应用程序的后端。此代码在正常的 django 查询中工作正常:

def get_myobj():
        cache_key = 'mykey'
        result = cache.get(cache_key, None)
        if not result:
            result = Product.objects.all().filter(draft=False)
            cache.set(cache_key, result)
        return result

但与 django-rest-framework api 调用一起使用时它不起作用:

class ProductListAPIView(generics.ListAPIView):
    def get_queryset(self):
        product_list = Product.objects.all()
        return product_list
    serializer_class = ProductSerializer

我即将尝试提供缓存功能的 DRF 扩展:

https://github.com/chibisov/drf-extensions

但 github 上的构建状态目前显示“构建失败”。

我的应用在 api 调用上的读取量很大。有没有办法缓存这些调用?

谢谢。

【问题讨论】:

  • 你用“@cache_response()”装饰方法了吗?
  • 嗨。 @cache_response 来自 DRF 扩展,我还没有尝试实现它,因为构建状态在他们的 github 页面上显示“构建失败”:github.com/chibisov/drf-extensions
  • 你意识到你粘贴的视图没有调用缓存?
  • 是的,我在 admin 中修改了值并重新加载了 drf web-browsable api。刷新后值总是改变。如果我没记错的话,默认超时应该是 5 分钟
  • 但是网站上的产品列表如果在 5 分钟内刷新,不会改变。所以我假设缓存正在工作(用于网站)

标签: python django caching django-rest-framework memcached


【解决方案1】:

我刚刚实现了这个以在我的序列化程序上使用

def cache_me(cache):
    def true_decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            instance = args[1]
            cache_key = '%s.%s' % (instance.facility, instance.id)
            logger.debug('%s cache_key: %s' % (cache, cache_key))
            try:
                data = caches[cache].get(cache_key)
                if data is not None:
                    return data
            except:
                pass
            logger.info('did not cache')
            data = f(*args, **kwargs)
            try:
                caches[cache].set(cache_key, data)
            except:
                pass
            return data
        return wrapper
    return true_decorator

然后我在我的序列化器上覆盖 to_representation 方法,因此它会缓存每个实例的序列化输出。

class MyModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = MyModel
        exclude = ('is_deleted', 'facility',)

    @cache_me('mymodel')
    def to_representation(self, instance):
       return super(MyModelSerializer, self).to_representation(instance)

【讨论】:

    【解决方案2】:

    好的,所以,为了对您的查询集使用缓存:

    class ProductListAPIView(generics.ListAPIView):
        def get_queryset(self):
            return get_myobj()
        serializer_class = ProductSerializer
    

    您可能希望在缓存集上设置一个超时时间(比如 60 秒):

    cache.set(cache_key, result, 60)
    

    如果要缓存整个视图:

    from django.utils.decorators import method_decorator
    from django.views.decorators.cache import cache_page
    
    class ProductListAPIView(generics.ListAPIView):
        serializer_class = ProductSerializer
    
        @method_decorator(cache_page(60))
        def dispatch(self, *args, **kwargs):
            return super(ProductListAPIView, self).dispatch(*args, **kwargs)
    

    【讨论】:

    • 谢谢!完美运行。
    • 当我完全按照所示尝试时,我收到错误'ShopsList' object has no attribute 'method'。有什么想法吗?
    • 这是另一个问题,当前线程无法回答。
    • 是的@eugene,只需在URL路由器模式cache_page(YourView.as_view())中调用视图上的cache_page
    • @Linovia 在产品更新或创建时如何清除/刷新缓存?
    猜你喜欢
    • 2021-04-15
    • 2016-02-23
    • 2019-09-26
    • 2016-11-04
    • 1970-01-01
    • 2022-01-09
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多