View decorators can be used to restrict access to certain views. Django come with some built-in decorators, like login_required, require_POST or has_permission. They are really useful, but sometimes you might need to restrict the access in a different level of granularity, for example only letting the user who created an entry of the model to edit or delete it.
A simple way to solve this problem, without adding an if statement inside each function, is to write a custom decorator.
In this article I will take you into the basic steps of creating an app level decorator.
Sample scenario
To ilustrate this article, let’s pretend we have an app named blog.
models.py
views.py
urls.py
At this point, we have one model named Entry that relates to a User. We also have three views, to list, add or edit an existing entry. In our index page, we only list the blog entries that were created by the logged in User. But, nothing stops the User from changing the browser url to edit an Entry that wasn’t created by him.
We want to make sure the User only edit the Entries created by him.
Create the decorator module
The decorator module can live anywhere, but usually they are related to a specific app. I like to put it inside the app folder. In case it’s a decorator for general use, I put it in the same level as my settings.py and urls.py.
Create a new file named decorators.py:
The app folder structure:
Edit the decorators.py file creating a new function named user_is_entry_author:
We are basically getting the current entry instance and checking if the logged in user is the owner of the entry. If it returns true, we proceed, otherwise we raise and PermissionDenied exception. We could also redirect the user to other page, like the login page for example. But as it’s not an expected behavior (it’s not meant to happen if the user follow the application flow clicking on the page and so on), it doesn’t really need to have a user friendly message or behavior.
Take the decorator into use
Inside your views.py, import our new decorator and add it to the edit view:
That’s it! Now only the user who have created the entry can edit it.
This solution can looks like an overkill in this small example. Of course if you only need to verify the ownership of the entry in the edit view, it’s better and cleaner to put the if statement inside the edit view. But, if your app starts to grow, it’s gonna be really handy. For example, consider we add this two new view functions in our views.py:
Both view functions can only be accessed by the entry owner and we don’t need to add the if statement inside each of them.
If you want to see more example of custom decorators, I have a few on my open source projects Bootcamp and Parsifal