I have a few
ListAPIViews (one example code below) that I would like to cache to improve performance (my queries are bit more complex and take hundreds of ms).
This implementation works, but it caches based on the URL, which is not optimal for me. The URL has parameter
locale which can be basically any country code. But I am mapping this locale to 8 region ids and for those the results are the same.
I would also want to customize the response based on one header - similar situation to the locale → region, so
vary_on_headers decorator won’t help me there.
Ideally I would like to keep the below implementation, but with the ability to transform the incoming request into cache key and return cached data if exists.
permission_classes = [permissions.AllowAny]
serializer_class = GameSerializer
pagination_class = GamesPagination
@method_decorator(cache_page(45 * 60))
def get(self, *args, **kwargs):
return super().get(*args, **kwargs)
Is this even a good idea? Wouldn’t it be better to move to
APIView to get more control?
As for the actual caching I plan to use Redis, as I did for other endpoint - DRF: View response 300-600ms, time to optimize? - #14 by nemecek_f
I started browsing my way through the CacheMiddleware to see just how deep that rabbit hole goes - and to me, it appears to go pretty deep. (
cache_page is defined as the output from
decorator_from_middleware_with_args(CacheMiddleware), which itself comes from
make_middleware_decorator, which takes a middleware class and returns a view decorator)
What follows is all conjecture - I’ve never done anything like this -
If I were looking at this type of situation, I’d probably create a custom cache more directly oriented toward handling this specific case - something that is more tuned to caching based upon the url patterns that you wish to manage.
If you want to keep the specific semantics (using
method_decorator) and the name
cache_page for the decorator, you could probably create your own middleware class for your own
cache_page function, and import it in your view instead of the one from
(Actually, now that I think about it, i did once create a custom middleware to examine url patterns to collect certain metrics. While the use-case wasn’t identical, the basic idea was the same - match url patterns based upon different parts of the url and record data accordingly.)
I have very little experience with middlewares so this is quite surprising approach to me. Is the main reason that the existing
ListAPIView isn’t really meant for more complex customizations and using the
APIView seems like too much repetitive work?
From what I can gather, it’s more of a DRY situation than anything else. The fundamental cache functions are in the middleware, providing this convenience function really only allows that middleware to be applied and used on a per-view basis.
Someone else would need to address that - I’ve only used DRF in the most primitive and fundamental situations. I’m looking at this from the perspective of a typical Django view, not accounting for any of the functionality added by the DRF views.