Django 1.10: "new style" middleware equivalent of `process_request()` - django

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)

Related

Django Middleware does not modify request in tests

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'))

How to wrap custom endpoints in Django Tastypie?

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

Django set last_online middleware not working

I want to log the last time my user has accessed the website and have implemented this middleware. It however does not store the most updated time.
middleware.py
class LastOnlineMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_request(self, request):
if request.user.is_authenticated():
request.user.profile.last_online = timezone.now()
request.user.profile.save()
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
last_online = models.DateTimeField(default=timezone.now)
It dose not work because process_request is not called in __call__ function.
You should change __call__ function like below.
def __call__(self, request):
self.process_request(request)
return self.get_response(request)
or to make LastOnlineMiddleware subclass of django.utils.deprecation.MiddlewareMixin.
If you use MiddlewareMixin, there is no need to define __init__ and __call__ function. You just needed to define process_request function written in the question.

How do I password protect all but one URL in Django without authentication?

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.

Insert custom field in Django response using middleware

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