Question

Each user in my Django application is associated with a department, and virtually every request involves some department-related processing. So I'd love to make the department object available across the entire application.

Which of these, if any, is the most appropriate approach to take:

  1. Custom middleware that simply retrieves the related department from the DB and attaches it to the request object, say as request.department, sort of like Django's AuthenticationMiddleware makes the currently logged-in user available at request.user. (See, e.g., here and here)
  2. Placing the department in the session when the user logs in, and subsequently retrieving it in views using Django's request.session interface.

I haven't had an opportunity to get familiar with Django's caching features yet, but I'd like to eventually cache the department on a per-user basis to avoid the extra DB hit on every request. I see that Django's sessions provide built-in caching support. I also imagine that caching can be implemented with the first approach as well.

Is there an advantage to using sessions (#2 above) over custom middleware (#1 above) for this kind of thing? The middleware approach seems cleaner from an internal API standpoint, but I'm guessing this is exactly the kind of thing sessions are designed for -- so perhaps this is the right opportunity to start using them?

Thanks for any guidance!

Was it helpful?

Solution

Basically both approaches are quite similar. request.session approach can just get eliminate an extra step with setting up a caching in middleware manually. The bad thing about session approach is that the data is not guaranteed to be available if you use cache storage out of box. For example, there can be 0.1% of users with disabled cookies, you are using memcache storage there can be a necessity to restart your memcache server on redeploy and your logged-in users will lost their data, etc. In summary, I would not use sessions with cache storage for crucial data. In my projects I prefer to use 1st option as it gives me a greater level of control.

You can set up have special middleware adding view_name variable to the request and enabling to control where and what to show:

class NameMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        # add current view
        if isinstance(view_func, str):
            request.view_name = view_func
        elif hasattr(view_func, '__name__'):
            request.view_name = view_func.__name__

Then, you will have a greater control on where to provide additional information to the request, for example in context_processors you can attach department inf only to the selected views and cache a result in an efficient way(proxing a request to the database if you want):

def department_context_processor(request):
    if hasattr(request, 'view_name'):
        if request.view_name == 'department_view1' or request.view_name == 'department_view2':
            departments = cache.get('department_'+str(request.user), None)
            if departments is None:
                departments = Department.objects.filter(user=request.user)
                cache.set('department_'+str(request.user), departments, 60*60)
            if departments:
                return {
                    'departments': departments
                }
    return {}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top