How can I add field to request body in django middleware - django

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.

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

Pass extra arguments from middleware to view

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

Finding the decorator name using django middleware

I had created a decorator to check if a person has session as follows:
(comments added for brevity)
def session_enabled(func=None, prefix='calling: '):
# some preprocessing
def session_enabled_wrapper(*args, **kwargs):
# check for session in request obj
# execute the function and get result onto a variable say result
# some API profiling logic
return result
return session_enabled_wrapper
I have used this on some views as follows:
#session_enabled
#csrf_exempt
def view_function(request):
# some processing
My goal was to check if any function are being accessed without this decorator in place on the logs.
So i wrote a middleware as follows:
class SessionEnabledMiddleware(object):
'''
class that represents middleware called during requests
'''
def process_view(self, request, view_func, view_args, view_kwargs):
'''
called during the request cycle
:param request: request param
:param view_func: view function object
:param view_args: args passed to view function
:param view_kwargs: kwargs passed to view function
:return: None
'''
print('############# Inside session enabled middleware ###################')
if not view_func.__name__ == 'session_enabled_wrapper':
print('Function Not session enabled', request.path)
else:
print('function is session enabled', request.path)
I added the above middleware to tuple of MIDDLEWARE_CLASSES in settings.py file.
I was happy as this worked, but the happiness was short lived as my APIs started to crash with 403 forbidden error.
After some research, i changed the decorator as follows:
import functools
def session_enabled(func=None, prefix='calling: '):
# some preprocessing
#wraps(func)
def session_enabled_wrapper(*args, **kwargs):
# check for session in request obj
# execute the function and get result onto a variable say result
# some API profiling logic
return result
return session_enabled_wrapper
This meant that my earlier middleware logic failed. I needed to overcome this. So changed my middleware and decorator as follows:
decorator:
def session_enabled(func=None, prefix='calling: '):
# some preprocessing
#wraps(func)
def wrapper(*args, **kwargs):
wrapper.session_enabled = True
# check for session in request obj
# actual function execution and get result onto a varible say result
# some API profiling logic
return result
wrapper.session_enabled = False
return wrapper
middleware:
class SessionEnabledMiddleware(object):
'''
class that represents middleware called during requests
'''
def process_view(self, request, view_func, view_args, view_kwargs):
'''
called during the request cycle
:param request: request param
:param view_func: view function object
:param view_args: args passed to view function
:param view_kwargs: kwargs passed to view function
:return: None
'''
print('############# Inside session enabled middleware ###################')
if not view_func.session_enabled:
print('Function Not session enabled', request.path)
else:
print('function is session enabled', request.path)
But i was greeted with function object has no attribute 'session_enabled'.
I even tried:
view_function.__closure__[0].cell_contents.__name__
but couldn't get the name of the decorator.
What am i doing wrong? Is there any possible way to get the name of the decorator to be used as a condition in middleware or a way to find if the function is decorated and take necessary actions?
Note:
Stackoverflow question which almost meet the above requirement:
Detect Decorator in Python
EDIT:
After considering Vitor Freitas recommended link i changed the code as follows:
#register(session_enabled, csrf_exempt)
def view_function(request):
# some processing
middleware:
class SessionEnabledMiddleware(object):
'''
class that represents middleware called during requests
'''
def process_view(self, request, view_func, view_args, view_kwargs):
'''
called during the request cycle
:param request: request param
:param view_func: view function object
:param view_args: args passed to view function
:param view_kwargs: kwargs passed to view function
:return: None
'''
try:
print('############# Inside session enabled middleware ###################')
decorators = [decorator.__name__ for decorator in view_func._decorators]
if 'session_enabled' in decorators:
print('Function is session enabled', request.path)
except:
print('function is not session enabled or decorated using register', request.path)
Work's like a charm.....

request.POST returns old values after updating it in custom middleware - django 1.11.9

I am using django 1.11.9
I want to add client_id and client_secret to the django POST request.
Here is how my middleware.py file looks like:
class LoginMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# auth_header = get_authorization_header(request)
# Code to be executed for each request before
# the view (and later middleware) are called.
#Add Django authentication app client data to the request
request.POST = request.POST.copy()
request.POST['client_id'] = '12345678'
request.POST['client_secret'] = '12345678'
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
Middleware is being successfully processed when I check it with a debugger. Thought when a view is called the 'client_id' and 'client_secret' fields are missing in the request.
After some experimenting i figure out that request is not getting updated and when it is called in a different view, it returns old values.
I am later using request in rest_framework_social_oauth2. And this is the point when 'client_id' and 'client_secret' disappear.
class ConvertTokenView(CsrfExemptMixin, OAuthLibMixin, APIView):
"""
Implements an endpoint to convert a provider token to an access token
The endpoint is used in the following flows:
* Authorization code
* Client credentials
"""
server_class = SocialTokenServer
validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
oauthlib_backend_class = KeepRequestCore
permission_classes = (permissions.AllowAny,)
def post(self, request, *args, **kwargs):
import pdb ; pdb.set_trace()
# Use the rest framework `.data` to fake the post body of the django request.
request._request.POST = request._request.POST.copy()
for key, value in request.data.items():
request._request.POST[key] = value
url, headers, body, status = self.create_token_response(request._request)
response = Response(data=json.loads(body), status=status)
for k, v in headers.items():
response[k] = v
return response
I need to add client_id and client_secret to the request body, so it can be later used by rest_framework_social_oauth2.
What could be the problem? How to properly update the request?
As you're working with request and processing a request, you have to implement process_request method, so the result will be something like:
class LoginMiddleware(object):
def process_request(self, request):
request.session['client_id'] = '12345678'
and then in your view:
def your_view(request):
client_id = request.session['client_id']

Django: how to set content-type header to text/xml within a class-based view?

I'm trying to do it this way, but it doesn't work.
class MyView(View):
def options(self, request, *args, **kwargs):
"""
Handles responding to requests for the OPTIONS HTTP verb.
"""
response = http.HttpResponse()
if self.kwargs.has_key('xml'):
response['Content-Type'] = 'text/xml; charset=utf-8'
return response
You don't need to write additional code. Use TemplateResponseMixin and set content_type attribute to whatever you need:
class MyView(TemplateResponseMixin):
content_type='application/xml'
...
I think the key point is render_to_response in django.views.generic.base , whose code is this:
def render_to_response(self, context, **response_kwargs):
"""
Returns a response, using the `response_class` for this
view, with a template rendered with the given context.
If any keyword arguments are provided, they will be
passed to the constructor of the response class.
"""
response_kwargs.setdefault('content_type', self.content_type) # key
return self.response_class(
request=self.request,
template=self.get_template_names(),
context=context,
**response_kwargs
)
As for your case, May be you need this code:
class MyView(ListView):
def get(self, request, *args, **kwargs):
context = self.get_context_data()
if self.kwargs.has_key('xml'):
return self.render_to_response(context, content_type="text/xml; charset=utf-8")
return self.render_to_response(context)
I made a middleware class based off of django-cors-headers so I could allow iframe-ing of part of my django app. I keep a middleware.py in my main project directory and save a couple random middleware classes I have made there, like this one here and a ForceResponse Exception for example.
import re
from django import http
from django.conf import settings
class XFrameAllowMiddleware(object):
def process_request(self, request):
"""
If CORS preflight header, then create an
empty body response (200 OK) and return it
Django won't bother calling any other request
view/exception middleware along with the requested view;
it will call any response middlewares
"""
if (self.is_enabled(request) and
request.method == 'OPTIONS' and
"HTTP_ACCESS_CONTROL_REQUEST_METHOD" in request.META):
response = http.HttpResponse()
return response
return None
def process_response(self, request, response):
if self.is_enabled(request):
response['X-Frame-Options'] = 'ALLOWALL'
return response
def is_enabled(self, request):
return re.match(settings.XFRAME_URLS_REGEX, request.path)
Add it to your MIDDLEWARE_CLASSES and configure the regex in your settings:
MIDDLEWARE_CLASSES = (
...
'your_django_app.middleware.XFrameAllowMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
)
XFRAME_URLS_REGEX = r'^/iframe_this_url/.*$'
from the django-cors-headers read.me:
CORS_URLS_REGEX: specify a URL regex for which to enable the sending of CORS headers; Useful when you only want to enable CORS for specific URLs, e. g. for a REST API under /api/.
Example:
CORS_URLS_REGEX = r'^/api/.*$'
Default:
CORS_URLS_REGEX = '^.*$'