In part 1 of this series, you learned the fundamentals of Django models and views. In part 2, you learned about user management. In this tutorial, youâll see how to combine these concepts to do Django view authorization and restrict what users can see and do in your views based on their roles.
Allowing users to log in to your website solves two problems: authentication and authorization. Authentication is the act of verifying a userâs identity, confirming they are who they say they are. Authorization is deciding whether a user is allowed to perform an action. The two concepts go hand in hand: if a page on your website is restricted to logged-in users, then users have to authenticate before they can be authorized to view the page.
Django provides tools for both authentication and authorization. Django view authorization is typically done with decorators. This tutorial will show you how to use these view decorators to enforce authorized viewing of pages in your Django site.
By the end of this tutorial youâll know how to:
- Use
HttpRequest
and HttpRequest.user
objects
- Authenticate and authorize users
- Differentiate between regular, staff, and admin users
- Secure a view with the
@login_required
decorator
- Restrict a view to different roles with the
@user_passes_test
decorator
- Use the Django messages framework to notify your users
If youâd like to follow along with the examples youâll see in this tutorial, then you can download the sample code at the link below:
Getting Started#
To better understand authorization, youâll need a project to experiment with. The code in this tutorial is very similar to that shown in part 1 and part 2. You can follow along by downloading the sample code from the link below:
All the demonstration code was tested with Python 3.8 and Django 3.0.7. It should work with other versions, but there may be subtle differences.
Creating a Project#
First, youâll need to create a new Django project. Since Django isnât part of the standard library, itâs considered best practice to use a virtual environment. Once you have the virtual environment, youâll need to take the following steps:
- Install Django.
- Create a new project.
- Create an app inside the project.
- Add a templates directory to the project.
- Create a site superuser.
To accomplish all that, use the following commands:
$ python -m pip install django==3.0.7
$ django-admin startproject Blog
$ cd Blog
$ python manage.py startapp core
$ mkdir templates
$ python manage.py migrate
$ python manage.py createsuperuser
Username: superuser
Email address: superuser@example.com
Password:
Password (again):
You now have a Blog
project, but you still need to tell Django about the app you created and the new directory you added for templates. You can do this by modifying the Blog/settings.py
file, first by changing INSTALLED_APPS
:
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"core",
]
The highlighted line indicates the addition of the core
app to the list of installed apps. Once youâve added the app, you need to modify the TEMPLATES
declaration:
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [os.path.join(BASE_DIR, "templates")],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
The highlighted line indicates the change you need to make. It modifies the DIRS
list to include your templates
folder. This tells Django where to look for your templates.
Note: Django 3.1 has moved from using the os
library to pathlib
and no longer imports os
by default. If youâre using Django 3.1, then you need to either add import os
above the TEMPLATES
declaration or convert the "DIRS"
entry to use pathlib
instead.
The sample site youâll be working with is a basic blogging application. The core
app needs a models.py
file to contain the models that store the blog content in the database. Edit core/models.py
and add the following:
from django.db import models
class Blog(models.Model):
title = models.CharField(max_length=50)
content = models.TextField()
Now for some web pages. Create two views, one for listing all the blogs and one for viewing a blog. The code for your views goes in core/views.py
:
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from core.models import Blog
def listing(request):
data = {
"blogs": Blog.objects.all(),
}
return render(request, "listing.html", data)
def view_blog(request, blog_id):
blog = get_object_or_404(Blog, id=blog_id)
data = {
"blog": blog,
}
return render(request, "view_blog.html", data)