scalopus
scalopus

Reputation: 2710

Is the Global Request variable in Python/Django available?

I have written a plugin that sends a signal to activate my code. However, it doesn't send the user-request object to my code. I am looking for a way to retrieve the current request without modifying the main application. I cannot find any documentation related to global request (like $_SERVER['REMOTE_ADDR'] in PHP).

I would like to know if there are any variable to do like that in Python/Django.

Upvotes: 19

Views: 17837

Answers (7)

rabbit.aaron
rabbit.aaron

Reputation: 2589

Now you could just use contextvars to store the request

# myapp/context.py
from contextvars import ContextVar
request = ContextVar("request", default=None)
# myapp/middleware.py
from asgiref.sync import iscoroutinefunction
from django.utils.decorators import sync_and_async_middleware
from myapp import context

@sync_and_async_middleware
def global_request_middleware(get_response):
    if iscoroutinefunction(get_response):
        async def middleware(request):
            context.request.set(request)
            response = await get_response(request)
            return response
    else:
        def middleware(request):
            context.request.set(request)
            response = get_response(request)
            return response

    return middleware
# settings.py

MIDDLEWARES = ["myapp.middleware.global_request_middleware", ...]
# getting the request
from myapp import context

def randomfunc():
    request = context.request.get()

Resources

Upvotes: 1

Teekin
Teekin

Reputation: 13279

One solution is django-middleware-global-request.

It provides a way to get the request from anywhere once the request has been constructed by Django in the first place. It returns None if no request object is available, for example when running in a manage.py shell.

Upvotes: 0

x-yuri
x-yuri

Reputation: 18863

Based on Ned Batchelder's reply I've compiled a solution. Although I wouldn't recommend it for anything but debugging/troubleshooting. There's a better solution on the linked page.

Put module m1 at a project root:

import inspect
def get_request():
    for f in inspect.stack():
        f_code = inspect.getmembers(f.frame, inspect.iscode)[0][1]
        f_locals = [v for (n, v) in inspect.getmembers(f.frame) if n == 'f_locals'][0]
        co_varnames = [v for (n, v) in inspect.getmembers(f_code) if n == 'co_varnames'][0]
        if 'request' in co_varnames:
            return f_locals['request']

Then in any other file:

import m1
print(m1.get_response().path)

You might want to make sure you don't introduce reference cycles. I haven't understood under which particular conditions I must do what exactly. Not that it matters in my case. But your mileage might vary.

Upvotes: 1

woryzower
woryzower

Reputation: 976

you can attach it to current request via middleware and retrieve it back https://github.com/jedie/django-tools/blob/master/django_tools/middlewares/ThreadLocal.py

Upvotes: 1

guettli
guettli

Reputation: 27816

AFAIK it is not available, except you make it available.

You can copy+paste the snippets provided in the other answers, or you can use this library: https://pypi.python.org/pypi/django-crequest

Middleware to make current request always available.

Upvotes: 4

Ned Batchelder
Ned Batchelder

Reputation: 375574

Django doesn't provide a global request object (it would actually be a thread local, not a global). But there are a few techniques you can use to get the same effect yourself: http://nedbatchelder.com/blog/201008/global_django_requests.html

Upvotes: 23

Niklas B.
Niklas B.

Reputation: 95308

As I know it, you define your Django view using a number of methods like:

def detail(request, some_param):
  # [...]

The parameter request contains information about the HTTP request. request.META['HTTP_X_FORWARDED_FOR'] for example, returns the client's IP address.

If your plugin has something to do with requests, its classes and function probably will be instantiated/called from your view. This means you need to pass it the current request object, as it makes no sense to have a global request object around. In PHP, this is possible, as every request causes the whole code to be executed from scratch, but in Django requests are dispatched by a server and passed around in the framework using HttpRequest objects. Also refer to this part of the Django documentation for more information.

Upvotes: -1

Related Questions