Pass extra arguments from middleware to view - django

I want to add another field in my POST(JSON) request. The key-value pair has to be "request id". I have concluded that the best way would be to generate a random request id and inject it into the request object using middleware. I have written a custom middleware for this. I am getting an error when I try to hit the endpoint.
I have tried searching through the internet but haven't found a solution to my error.
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
req = json.loads(request.body)
req_id = random.randint(0,1000000)
req["req_id"]=req_id
response = self.get_response(req)
# Code to be executed for each request/response after
# the view is called.
return response
The error I am getting is 'dict' object has no attribute 'is_ajax'.
Can you please help me fix this and if there is an easier and better way to implement this, please let me know.

Okay. I achieved what I was trying to do. My code for custom middleware is:
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
def process_view(self, request, view_func, *view_args, **view_kwargs):
request.req_id = random.randint(0,1000000)
Update: I was a noob back then and now reading the comments I feel embarrassed :P

Related

Django computing variable vaue in custom middleware and passing to all view functions

I am using Django 3.2. I want to compute the value of variable and make that value available to all views in my project.
I have decided to use middleware - but it is not clear (yet), how I can make the value I computed in MyCustomMiddleware available in a view.
Here is my custom middleware class:
class MyCustomMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
mysecret_value = 4269
return response
After making the requisite modifications to the MIDDLEWARE section in settings.py, how do I acesss mysecret_value in my views?
myapp/views.py
def foobar(request):
the_value = mysecret_value # <- how do I access the RHS variable?
Middlewares run before views, so you can actually modify the request object:
class MyCustomMiddleware:
...
def __call__(self, request):
request.mysecret_value = 4269
return self.get_response(request)
Then you can access this value from any view:
def foobar(request):
the_value = request.mysecret_value

How can I handle POST data in django middleware?

I have Django middleware to handle POST request.
class MyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, req):
response = self.get_response(req)
# want to do something with 'r.body',
# but it is not able to be read
return response
As the request body is already read in get_response, I cannot read it again in middleware.
Tried copy.copy(), but no luck since the copied stream references same object of the original one. copy.deepcopy() raises an exception.
How can I handle POST data in middleware?
I want to handle all requests, so implementing the logic in every view is not ideal.
Found solution
class MyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, req):
req.body # just add this line BEFORE get_response
response = self.get_response(req)
return response

Implement Django middleware for response behaviour

I'm a bit confused by the middleware description in the official django docs and can't seem to wrap my head around it.
When implementing class-based middleware it looks something like this (ex. from docs):
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
return response
The middleware gets called for requests as well as for response. This is my first question:
How do I implement different behavior depending on if I'm processing a request or a response?
Also, and this is related, I'm a bit confused because there also seems to be an old deprecated way of writing middleware where it was possible to overwrite the methods process.request() and process_response(). I'm not sure if this way of writing middleware is inadvisable now. Usually, the Django docs are spot on but this part is a little confusing (to me).
Can someone clear this up for me?
Basically the codes before responses = self.get_response(request) should process the request. self.get_response() will get the response from view, then codes after that should process the response. Finally you need to return the response from the function. Here is a visualization:
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Codes here will process the request
# -----------------------------------
response = self.get_response(request)
# -----------------------------------
# Codes here will process the response
return response

How can I add field to request body in django middleware

I want to add new field in request body in middleware and use it in views.
I googled it but the results was not worked.
How can I do it?
Django v2 python 3.6
You need to add a separate custom middleware which will process the request before landing to a particular view. Below is the code for custom middleware:
class ProcessRequestMiddleware(MiddlewareMixin):
"""
This middleware appends new payload in request body
"""
def process_view(self, request, view_func, *view_args, **view_kwargs):
request_data = getattr(request, '_body', request.body)
request_data = json.loads(request_data)
# here you can write the logic to append the payload to request data
request._body = json.dumps(request_data)
return None
Note - The middleware was place inside an app common (common/middleware/custommiddleware.py)
Now add this middleware to settings.MIDDLEWARE list:
"common.middleware.custommiddleware.ProcessRequestMiddleware"
Now you can retrieve the payload, which you had appended in custommiddleware, inside any of the views you want by just calling the json.loads(request.body).
Try following code:
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
my_request = request.GET.copy()
my_request['foo']='bar'
request.GET = my_request
response = self.get_response(request)
return response
I tried this for you: added above code into: example.py Then added 'example.SimpleMiddleware', into MIDDLEWARE
My view method:
def index(request):
for key in request.GET:
print (key, '--->', request.GET[key])
return render(request, 'example.html')
able to print foo ---> bar browser sends the request.

Why Django doesnt have Error Page Handler for 405 - Method Not Allowed?

When i read Django documentation i found only handlers for:
400,
403,
404,
500 errors.
Why 405 error handler doesn't exists but decorators like require_POST() is in common use?
The point is, what is proper way to create custom error page for Method Not Allowed error ?
I resolve my problem using Django Middleware maybe this will help someone
from django.http import HttpResponseNotAllowed
from django.shortcuts import render
class HttpResponseNotAllowedMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if isinstance(response, HttpResponseNotAllowed):
return render(request, '405.html', status=405)
return response
If you want a different response for each view, you can overwrite your function like:
class someView(View):
....
def http_method_not_allowed(self, request, *args, **kwargs):
return HttpResponse("Not available")
If you wanna know what the function does check https://github.com/django/django/blob/master/django/views/generic/base.py#L90