Django rest framework custom Response middleware
Asked Answered
G

2

3

I use Django Rest Framework with rest_auth (/login, /logout/, /register...) I have a Middleware, normally triggered by user_logged_in or user_logged_out signals.

In my Middleware, I want to use Response object from Rest framework.

My middleware.py

from django.contrib.sessions.models import Session
from django.contrib.auth import logout
from django.contrib.auth.models import AnonymousUser
from rest_framework.response import Response
from rest_framework import status


class OneSessionPerUserMiddleware:
    def __init__(self, get_response):

        self.get_response = get_response

    def __call__(self, request):

        if request.user.is_authenticated:
            if request.user.session_key != Session.objects.filter(session_key__in = request.user.session_key):
                logout(request)
                return Response(request)
        return self.get_response(request)

I suppose that I pass my condition, but I get this error :

 The response content must be rendered before it can be accessed

How to use correctly the API Response object in a middleware ?
And I don't understand really what is : self.get_response = get_response ?

Gasify answered 1/5, 2019 at 13:53 Comment(3)
just remove your return Response(request). Let your views process the request with return self.get_response(request). You should handle the logged out case gracefully anyway.Fiester
So I can't use the default API display to add some custom message "already logged" , for example ?Gasify
if you really want to handle this for all requests in your middleware, regardless of the api view being called, then see the answer given by Nafees.Fiester
D
9

return Response(request) is not something django can handle. Ps you are passing request object to Response what does that mean?

Actually Request and Response classes from rest framework are not compatible with django. rest framework wraps WSGIRequest (django's builtin) with Request object in APIView and after getting Response object from view, it creates HttpResponse object by unwrapping it. So Response object can only be used in rest framework views. You can use JsonResponse from django.http in middleware like this

from django.http import JsonResponse


if request.user.is_authenticated:
    if request.user.session_key != Session.objects.filter(session_key__in = request.user.session_key):
        logout(request)
        return JsonResponse({'logout': True}) # or whatever data you want to return 
return self.get_response(request)
Dandelion answered 1/5, 2019 at 14:50 Comment(0)
A
3

First of all: if you are using something other than rest_framework.authentication.SessionAuthentication as an authentication_class, then request.user is set outside of middlewares (somewhere during View.dispatch)

If you are sure that request.user is always corresponding to request.user inside rest_framework views and just want to return a response:

A. Look at the APIView.finalize_response: it's relatively "complex" because it can use different renderers (depending on accept-content request header), it may change headers. If you can access instance of your view in the middleware, then you can call view.finalize_response(request, response), if you don't have it then you can try doing rest_framework.views.APIView().finalize_response(...)

B. You can use django.http.HttpResponse: manually generate string for body, and specify appropriate content_type. And django.http.JsonResponse may be handy too.

C. I assumed that instead of return Response(request) you really are doing something else (like Response(data=...)). If you just need to return results from view, then remove return Response(request), so that return self.get_response(request) kicks in. But you are making a logout, so maybe you should return some instance of django.http.HttpResponseRedirect

Appointive answered 1/5, 2019 at 14:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.