I am looking for the right directions to add a custom field in the HTTP response using middleware and access the custom field in the JavaScript front-end.
I am trying to implement this, but on receiving the response on the JavaScript side there is no field like "is_logged" in the body.
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.user.is_authenticated:
response = self.get_response(request)
response.body['is_logged'] = True
else:
response = self.get_response(request)
response.body['is_logged'] = False
return response
Related
I am trying to create test class for my custom middleware. The project is using Django REST framework. Middleware class works fine when server is running, but when I run test it behaves not quite as I would expect it to do. Maybe I misunderstood something, as I am quite new to testing in Django.
my_middleware.py:
class FX:
a = False
b = None
c = ''
def __init__(self) -> None:
pass
def __str__(self):
return 'fx ok'
class MyMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request.fx = FX()
response = self.get_response(request)
print('done')
return response
views.py:
class TestView(APIView):
def get(self, request, format=None):
print('View ok')
print('FX: ', request.fx)
return Response({'result':'ok'})
tests.py:
class TestMyMiddleware(APITestCase):
#classmethod
def setUpTestData(cls):
pass
def setUp(self):
pass
def test_fx(self):
response = self.client.get(reverse('TestView'), content_type="application/json")
request = response.request
self.assertTrue(hasattr(request, 'fx'))
The code above actually runs the middleware. It prints "done" form the middleware call, then prints 'View ok' and also prints FX instance. However request.fx is not available in the test_fx method, thus giving assertion failure:
self.assertTrue(hasattr(request, 'fx'))
AssertionError: False is not true
Any idea what I might be doing wrong?
You need to access the request object from the response with response.wsgi_request instead of response.request.
class TestMyMiddleware(APITestCase):
#classmethod
def setUpTestData(cls):
pass
def setUp(self):
pass
def test_fx(self):
response = self.client.get(reverse('TestView'), content_type="application/json")
request = response.wsgi_request
self.assertTrue(hasattr(request, 'fx'))
I want to add a dispatch method to some resource so I could use a wrapper decorator on it.
The issue is that it only works on the CRUD operations and wont go into the dispatch method on 'original' endpoints:
class SomeResource(SomeBaseResource):
class Meta(...): ...
def get_something_extra(self, request, **kwargs):
...
def patch_detail(self, request, **kwargs):
...
and the base resource:
class SomeBaseResource(ModelResource):
class Meta(...): ...
# the wrapper
#decorator_to_wrap_all_methods_with(...)
def dispatch(self, request_type, request, **kwargs):
logger.info('Enter')
response = super(SomeBaseResource, self).dispatch(request_type, request, **kwargs)
logger.info('Exit')
return response
So when I use patch request it is working as expected, but wont on calling the get_something_extra api.
How do I wrap ALL methods in resource?
A workaround solution is to add Middleware:
MIDDLEWARE = (
'my.basic.BaseMiddleware',
...
)
class BaseMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
#decorator_to_wrap_all_methods_with(...)
def __call__(self, request):
response = self.get_response(request)
return response
I need to check the Authorization HTTP Header of every incoming request.
First i have implemented Middleware. Now on website in devtools (when i post something) i see authorizational header with token.
class MyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
user_id = request.POST.get('created_by', False)
try:
api_token = CustomUser.objects.get(user=user_id).api_token
except MyUser.DoesNotExist:
api_token = ''
response = self.get_response(request)
response['Authorization'] = "Bearer " + api_token
return response
class MyApiView(mixins.ListModelMixin, viewsets.GenericViewSet):
queryset = Event.objects.all()
serializer_class = EventSerializer
#action(methods=['POST'], detail=False)
def post(self, request):
print(request.META['HTTP_AUTHORIZATION']) **#keyerror**
print(request.META['Authorization']) **#keyerror**
print(request.headers.items()) **#no authorization header**
tutorial_serializer = MyApiSerializer(data=request.data)
if tutorial_serializer.is_valid():
tutorial_serializer.save()
return Response(tut`enter code here`orial_serializer.data, status=status.HTTP_201_CREATED)
return Response(tutorial_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
You're assigning header to wrong entity. Instead of adding header to response (what Django will return back to client), you need to add it to request headers:
from django.utils.deprecation import MiddlewareMixin
class CustomHeaderMiddleware(MiddlewareMixin):
def process_request(self, request):
user_id = request.POST.get('created_by', False)
try:
api_token = CustomUser.objects.get(user=user_id).api_token
except CustomUser.DoesNotExist:
api_token = ''
request.META['HTTP_Authorization'] = "Bearer " + api_token
response = self.get_response(request)
return response
Is there a tool that allows me to password protect all but one URL in Django without requiring authentication?
You can write a custom middleware for this:
class LoggedInUserCheckMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
full_path = request.get_full_path()
if not full_path == '/no-need-auth-url' and not request.user.is_authenticated:
raise Http404
response = self.get_response(request)
return response
And add it to MIDDLEWARE in settings:
MIDDLEWARE = [
# rest of middlewares
'path.to.LoggedInUserCheckMiddleware'
]
you can use #loging_required decorator
from django.contrib.auth.decorators import login_required
on all your views except that one view/url.
How would one create "new style" middleware, which fulfills an equivalent implementation to using the process_request() hook with the "old style"?
I've already adapted pre 1.10 middleware process_request() using MiddlewareMixin...
from django.utils.deprecation import MiddlewareMixin
class MyCustomMiddleware(MiddlewareMixin):
def process_request(self, request):
# My request logic
return response
I'd like to know how to do a "pure" >1.9 "new style" implementation. I tried doing so by implementing __init__() and __call__() like this without luck:
class MyCustomMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# My request logic
return response
Thanks.
Here an example...
class TimeStampMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request.timestamp = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
response = self.get_response(request)
return response
Now you can get the timestamp in every request from yours views! (is only an example)