关于缓存:如何使用查询参数让服务器删除API调用缓存(django,DRF)

How to use a query parameter to have the server delete the API call cache (django, DRF)

我正在使用Django Rest Framework和DRF扩展(http://chibisov.github.io/drf-extensions/docs/#how-key-constructor-works)。

我有一个API调用/ user /:id / products,它提供了用户可以访问的产品的完整列表。因为这是一个昂贵的查询,所以我根据方法ID,格式,语言,用户和检索SQL查询来对其进行缓存。

我还有另一个API调用/ pay来处理我们所有的付款。产品ID是该API调用的POST参数。

用户付款后,立即将其定向到产品页面-但由于产品查询已缓存,因此它仍然显示产品的旧列表,而不是他们刚购买的新产品的更新列表。我知道cache.delete方法,但是很难从/pay获取密钥,因为这是完全不同的API调用。

我想做的是在/user/:id/products API调用中添加一个参数force_refresh,如果存在,则计算哈希键,就像force_refresh参数不存在一样,然后清除缓存对于那个关键。但是,我无法在drf-extension的缓存框架内的KeyConstructor中找到正确的位置来插入。让我知道让服务器知道删除此查询的缓存的最佳方法是什么?铅>


将所有GET参数用作DRF扩展缓存的示例作为ReadOnlyModelViewSet上的键哈希。

定义密钥构造函数(密钥哈希):

1
2
3
4
5
from rest_framework_extensions.key_constructor.constructors import DefaultKeyConstructor
from rest_framework_extensions.key_constructor.bits import QueryParamsKeyBit

class QueryParamsKeyConstructor(DefaultKeyConstructor):
    all_query_params = QueryParamsKeyBit('*')  # Don't change, * is default on drf-extension dev version only

您的看法:

1
2
3
class UserViewSet(ListCacheResponseMixin, viewsets.ReadOnlyModelViewSet):
    serializer_class = UserSerializer
    list_cache_key_func = QueryParamsKeyConstructor()

在settings.py中设置DRF扩展名和Django缓存设置,例如:

1
2
3
4
5
6
7
8
9
CACHES = {
   "default": {
       "BACKEND":"redis_cache.RedisCache",
       "LOCATION":"redis://127.0.0.1:6379/0"
    }
}

REST_FRAMEWORK_EXTENSIONS = {
'DEFAULT_CACHE_RESPONSE_TIMEOUT': 20

} ??


What I would like to do is add a parameter force_refresh to the /user/:id/products API call

我认为这不是一个好主意。如果您的客户端发出/pay请求,然后使用自己的路由到/user/:id/products怎么办?使用force_refresh属性,您正在为请求添加状态,并且状态不再是幂等的。

如果您具有较高的读取速率和较低的写入速率,我建议您根据后保存信号来考虑创建具有全局缓存无效性的自定义密钥位。

如果要使缓存失效更具体,建议您对用户模型进行非规范化。例如:

1
2
3
class User(UserBaseModel):
    ...
    products_updated_date = models.DateTimeField()

您每次付款时都应更新products_updated_date

1
2
3
4
5
6
7
8
class UserViewSet(CacheResponseMixin, ReadOnlyModelViewSet):
    ...
    @action('pay')
    def pay(self):
        ...
        self.request.user.products_updated_date = now()
        self.request.user.save()
        ...

最后,您应该使用用户的products_updated_date字段用法创建自定义密钥位:

1
2
3
4
5
6
7
8
9
10
11
from rest_framework_extensions.key_constructor.bits import (
    KeyBitBase
)

class UserProductsUpdatedKeyBit(KeyBitBase):
    def get_data(self, **kwargs):
        request = kwargs['request']
        if (hasattr(request, 'user') and
            request.user and
            request.user.is_authenticated()):
            return request.user.products_updated_date

您可以将UserProductsUpdatedKeyBit添加到密钥构造函数类中,以进行/user/:id/products路由。