4

What would be the best way of putting a bit of code to run for all views in a views.py file?

I come from a PHP background and I normally put this in the constructor/index bit so that it always ran whatever page is being requested. It has to be specific for that views.py file though, I want to check that the user has access to 'this app/module' and want to avoid having to use decorators on all views if possible?

Maxime Lorant
  • 34,607
  • 19
  • 87
  • 97
user2355278
  • 375
  • 2
  • 5
  • 15

2 Answers2

8

TL;DR

You should check about middlewares. It allows to execute some code before the view execution, the template rendering and other stuff.

Some words about middlewares

You can represent middlewares in your head like this:

Middleware concept

As you can see, the request (orange arrow) go through every middleware before executing the view and then can hitting every middleware after (if you want to do something before the template processing for example).

Using Django 1.10

Arcitecture of middlewares have changed in Django 1.10, and are now represented by simple function. For example, here's a counter of visits for each page:

def simple_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        try:
            p = Page.objects.get(url=request.path)
            p.nb_visits += 1
            p.save()
        except Page.DoesNotExist: 
            Page(url=request.path).save() 

        response = get_response(request)
        if p:
            response.content += "This page has been seen {0} times.".format(p.nb_visits)

        return response

    return middleware

And voilà.

Using Django

Here's an example of middleware, which would update a counter for each visit of a page (admit that a Page Model exists with two field : url and nb_visits)

class StatsMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        try:
            p = Page.objects.get(url=request.path)
            p.nb_visits += 1
            p.save()
        except Page.DoesNotExist: 
            Page(url=request.path).save() 

    def process_response(self, request, response):
        if response.status_code == 200:
            p = Page.objects.get(url=request.path)
            # Let's say we add our info after the html response (dirty, yeah I know)
            response.content += u"This page has been seen {0} times.".format(p.nb_visits)
        return response

Hopes this will help you :)

Maxime Lorant
  • 34,607
  • 19
  • 87
  • 97
1

Middleware is the solution but keep in mind the the order to define the middleware in the settings.py matters.

Kintarō
  • 2,947
  • 10
  • 48
  • 75