将基于缓存 Django 类的视图响应与请求中的参数绑定

Posted

技术标签:

【中文标题】将基于缓存 Django 类的视图响应与请求中的参数绑定【英文标题】:Bind cache Django class based view response with parameter from request 【发布时间】:2022-01-09 04:10:16 【问题描述】:

我想缓存我的 API 响应并将其与 GET 请求中存在的参数绑定。 请求如下所示:

GET /products?producent=some_company

这是我的简化课程:

class ProductsListCreate(generics.ListCreateAPIView):

    def list(self, request, *args, **kwargs):
        producent = request.query_params.get("producent")
        cached_response = cache.get(f"response-products-producent", None)
        if not cached_response:
            queryset = self.filter_queryset(self.get_queryset())
            page = self.paginate_queryset(queryset)
            serializer = self.get_serializer(page)
            response = self.get_paginated_response(serializer.data)

            cache.set(f"response-products-producent", response , timeout=20)
            return response

        return cached_response 

但是当我尝试缓存响应时,我收到了错误:

django.template.response.ContentNotRenderedError: The response content must be rendered before it can be pickled.

你有什么建议给我吗?当我试图弄清楚这一点时,我在这里搜索https://docs.djangoproject.com/en/3.2/topics/cache/。起初我尝试使用@cache_page 的方法,但它不允许我使用请求中的参数,所以我想要走的路是低级缓存API。

【问题讨论】:

if not cached_productsif not cached_response ?我认为这是第二个。 是的,抱歉,我编辑了它 第一个 cache_response this (cached_response = cache.get(f"response-products-producent", None) 你给它producent这个变量你定义了吗?你应该先给它分配一个使用前的值。 为什么不缓存查询集和模板,想要缓存所有的响应对象呢?您应该尝试缓存查询集并在您循环遍历产品的模板部分之后 在缓存中保存之前尝试将响应转换为字符串。 【参考方案1】:

错误消息实际上非常具有描述性。在尝试将其腌制为可缓存格式之前,您必须在响应上调用 render()。问题是:这将导致您进入一个兔子洞来解构响应并从缓存的数据中重建。 IMO,你最好缓存查询集。然而,这就是它的样子:

class ProductsListCreate(generics.ListCreateAPIView):

    def list(self, request, *args, **kwargs):
        producent = request.query_params.get("producent")
        response_triple = cache.get(f"response-products-producent", None)
        if not response_triple:
            queryset = self.filter_queryset(self.get_queryset())
            page = self.paginate_queryset(queryset)
            serializer = self.get_serializer(page)
            response = self.get_paginated_response(serializer.data)

            response.render()

            if not response.status_code >= 400:
                # django 3.0 has no .items() method, django 3.2 has no ._headers
                if hasattr(response, '_headers'):
                    headers = response._headers.copy()
                else:
                    headers = k: (k, v) for k, v in response.items()
                response_triple = (
                    response.rendered_content,
                    response.status_code,
                    headers
                )
                cache.set(f"response-products-producent", response_triple, timeout=20)
        else:
            # build smaller Django HttpResponse
            content, status, headers = response_triple
            response = HttpResponse(content=content, status=status)
            for k, v in headers.values():
                response[k] = v
        if not hasattr(response, '_closable_objects'):
            response._closable_objects = []

        return response

取自:https://github.com/chibisov/drf-extensions/blob/ecdf3a95d7f18ccf9cffa55809635c3715179605/rest_framework_extensions/cache/decorators.py#L63

【讨论】:

以上是关于将基于缓存 Django 类的视图响应与请求中的参数绑定的主要内容,如果未能解决你的问题,请参考以下文章

Django 之 Views视图理解

django-基于类的视图

Django编写RESTful API:基于类的视图

Django之视图

Django--基于类的视图的 URL 缓存失败

Django视图层--FBV与CBV