Lets say you have an API which is being used by many stores. Now for a specific store ABC, they want to have a different response format. So how would you make this implementation generic without making different views for store ABC? Simple, use middleware.
How it works ︎
First update the url like this:
url = [ path('api/v1/<str:store_code>/', include("api.urls")), ]
Then write a middleware to capture the value of
class StoreCodeMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) return response def process_view(request, view_func, view_args, view_kwargs): store_code = view_kwargs.get('store_code', None) if store_code: request.session['store_code'] = store_code
Here I am using
process_view to capture the url argument. Because in
process_view, there is a keyword argument named
view_kwargs which is a dictionary, which will be passed to the view. Now, we can attach the
request object through another middleware.
class StoreToRequestMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): store_code = request.session.get('store_code', None) if store_code: request.store, _ = Store.objects.get_or_create(code=store_code) # assuming `Store` is the model class where store information are being stored response = self.get_response(request) return response
Now lets add these middlewares in
MIDDLEWARES = [ # rest of the middlewares 'path.to.StoreCodeMiddleware', 'path.to.StoreToRequestMiddleware' ]
StoreCodeMiddleware is on top of
Lets say you have an API view, then use
store info like this:
class StoreAPI(APIView): def get(self, request, *args, **kwargs): serializer = CommonSerializer(request.store) if request.store.code == "ABC": serializer = ABCSerializer(request.store) return Response(serializer.data)
Another usage scenario ︎
Lets say you are using a package like black box which provides everything through url(means you can’t override anything inside the views or models), then the approach is useful. For example, when using
django-rest-auth, they provide authentication services(like login, registration, password reset etc), you just need to include their url in your root url. When using these libraries, you might need to store additional information coming through url; then the given approach is really helpful.
Hope it helps. Thanks for reading. Cheers!!
Last updated: July 2, 2020