Django url with dynamic prefix

I need to have a dynamic url prefix for all urls in my application.

I am familiar with static prefix for example url(r'^myprefix/app', include('app.urls'))

.

Instead, I need it to myprefix

be dynamic for example url(r'^(?P<prefix>\w+)/app', include('app.urls'))

.

It works, but here's the kicker. I don't want to be prefix

sent as a keyword argument to all views. I want to be able to capture it and use it in Middleware or something similar.


To give a concrete use case, we have software (this Django project) used to manage various test labs. The application needs knowledge about which laboratory it is working in.

I am currently doing it with the following:

class LabMiddleware(object):
    def process_request(self, request):
        request.current_lab = 'lab1'  # Note that this is currently hard coded

      

The requirement states that users will be able to navigate to a URL such http://host/<lab_name>/app

as where it lab_name

will be used in my LabMiddleware. Because of this, I obviously do not want to accept lab_name

in each of my views, as it is cumbersome and redundant.


UPDATE:

Based on what Sohan gave in his answer, I ended up using a custom middleware class:

urls.py

url(r'^(?P<lab_name>\w+)/', include('apps.urls')),

      

Applications / urls.py

url(r'^app1/', include('apps.app1.urls', namespace='app1')),

      

middleware.py

class LabMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        lab_name = view_kwargs.get('lab_name')
        if lab_name:
            request.current_lab = Lab.objects.get(name=lab_name)
            # Remove the lab name from the kwargs before calling the view
            view_kwargs.pop('lab_name')
            return view_func(request, *view_args, **view_kwargs)

      

settings.py

MIDDLEWARE_CLASSES = (
    # Default Django middleware classes here...
    'raamp.middleware.LabMiddleware',
)

      

This allowed me to get the lab name in the url and add it to the request. Then after removing it from view_kwargs

, it doesn't go to the view function and everything works as I intended.

Also note that the code I have above is not the most optimized (for example I am querying the database for every request). I removed the code I have for caching since it is not important to show how this problem was solved, but it is worth mentioning that some improvements need to be made to this code if you are using it on a production system.

+3


source to share


1 answer


You can create a decorator that wraps each view function. The decorator can take care of any processing you use in the lab name parameter, and each view doesn't need to see the parameter lab_name

.

def process_lab_name(request, lab_name):
    request.current_lab = lab_name

def lab(view_func):
    def _decorator(request, lab_name, *args, **kwargs):
        # process the lab_name argument
        process_lab_name(request, lab_name)
        # when calling the view function, exclude the lab_name argument
        response = view_func(request, *args, **kwargs)
        return response
    return wraps(view_func)(_decorator)

@lab
def some_view(request):
    return render(...)

      



And your route will look like url(r'^(?P<lab_name>\w+)/app'

+2


source







All Articles