Is modifying Django urlconf via set_urlconf and request.urlconf in a middleware safe?

Viewed 260

I am changing the default urlconf in a middleware based on the requested hostname and it's working as expected during development, however I am concerned about racing/threads as I am modifying a Django setting at runtime!

My concern is that Django would confuse the urlconfs with many concurrent requests. Is that a valid concern?

1 Answers

The TLDR Version

You shouldn't really need to use set_urlconf in your middleware. You are free to set request.urlconf without worrying about threads though.

For each request that django processes, it will either use ROOT_URLCONF or the value of request.urlconf if it has been set in the middleware, to decide what urlconf to use. For this reason you shouldn't need to use set_urlconf. Setting request.urlconf is the recommended way.

How it works

In fact, under the hood, after a request has passed through the middleware, django calls this function, to decide which urlconf to use, so if request.urlconf is set, then any calls to set_urlconf in the middleware will be irrelevant anyway:

# django.core.handlers.base.py

    def resolve_request(self, request):
        if hasattr(request, 'urlconf'):
            urlconf = request.urlconf
            set_urlconf(urlconf)
            resolver = get_resolver(urlconf)

Checkout how django proceeses a request from the official docs for more info.

Thread safety of set_urlconf

Also note that the implementation of set_urlconf is thread-safe:

# django.urls.base.py

# Overridden URLconfs for each thread are stored here.
_urlconfs = Local()


def set_urlconf(urlconf_name):
    """
    Set the URLconf for the current thread (overriding the default one in
    settings). If urlconf_name is None, revert back to the default.
    """
    if urlconf_name:
        _urlconfs.value = urlconf_name
    else:
        if hasattr(_urlconfs, "value"):
            del _urlconfs.value

(That is to say, it only affects the current thread.)

Related