Hello and welcome to this Python 3.7 and Django 2.2 tutorials, my name is Henry Mbugua and I will be taking through the various aspects of how to show a list of registered users, activating and deactivating users in Django. In our previous lessons, we learned how to create a custom dashboard and we are going to continue from where we left.
We left when we had developed the following custom dashboard:
In this tutorial, we are going to pull a list of the registered user in our systems. Create the ability to activate and deactivate them. This means when you don’t want a user to login to your system you deactivate them.
The point of a web framework in the 21st century is to make the tedious aspect of web development fast and Django is no exception. DRY is a principle in software development whose aim is to avoid repetition and avoid redundancy. Redundancy is bad, normalization is good.
Since our side navbar is going to exist on every page of our dashboard, we are going to create a folder in our templates called partials. Inside our partials folder, we are going to create two files, one called sidenavbar.html and the second one called top_navbar.html. Here is how the folder structure should look like.
Now make sure that top_navbar.html file has the following code:
<nav class="navbar navbar-light fixed-top bg-danger flex-md-nowrap p-0 shadow"> <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#" style="color: white">HLAB</a> <ul class="navbar-nav px-3"> <li class="nav-item text-nowrap"> <a class="nav-link" href="#" style="color: white">Sign out</a> </li> </ul> </nav>
Now make sure that the sidenavbar.html has the following code:
<nav class="col-md-2 d-none d-md-block bg-light sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg> Dashboard <span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg> User profiles </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-shopping-cart"><circle cx="9" cy="21" r="1"></circle><circle cx="20" cy="21" r="1"></circle><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path></svg> Notifications </a> </li> </ul> <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted"> <span>User Management</span> <a class="d-flex align-items-center text-muted" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg> </a> </h6> <ul class="nav flex-column mb-2"> <li class="nav-item"> <a class="nav-link" href=""> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg> Admins </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg> Login Audit </a> </li> </ul> </div> </nav>
Remember this is just separating code and this will help us reduce repetition when building our dashboard. The next step is to update our dashboard.html file. Make sure that dashboard.html file has the following code:
{% extends 'base.html' %} {% block content %} {# top navbar #} {% include 'partials/top_navbar.html' %} {# top navbar #} <div class="container-fluid"> <div class="row"> {# Side navbar #} {% include 'partials/sidenavbar.html' %} {# end of sidenavbar #} <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"><div class="chartjs-size-monitor" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: hidden; pointer-events: none; visibility: hidden; z-index: -1;"><div class="chartjs-size-monitor-expand" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;"><div style="position:absolute;width:1000000px;height:1000000px;left:0;top:0"></div></div><div class="chartjs-size-monitor-shrink" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;"><div style="position:absolute;width:200%;height:200%;left:0; top:0"></div></div></div> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h1 class="h2">Dashboard</h1> </div> </main> </div> </div> {% endblock %}
Let’s understand what we have done, on line 5 we include our top_navbar.html and on line 13 we include sidenavbar.html and this makes it easy to maintain the code if we wanted to change the navbar we only change this in one file thus DRY.
Showing List of Registered Users
Django automatically provides developers with a database-abstraction API that lets you create, retrieve, update and delete objects. In this section, we are going to retrieve all registered users. Open person_portfolio/views.py file and make sure it has the following code:
rom django.shortcuts import render, redirect from django.contrib.auth.forms import UserCreationForm from django.contrib.auth import login, authenticate from django.http import HttpResponse from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.contrib import messages def sign_up(request): if request.method == 'POST': form = UserCreationForm(request.POST) if form.is_valid(): form.save() username = form.cleaned_data.get('username') password = form.cleaned_data.get('password1') user = authenticate(username=username, password=password) login(request, user) return redirect('user_dashboard') else: form = UserCreationForm() return render(request, 'register.html', {'form': form}) @login_required() def user_dashboard(request): return render(request, 'dashboard.html') def sign_in(request): msg = [] if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user) return redirect('user_dashboard') else: msg.append('You account has been deactivated!') else: msg.append('Invalid Login credentials, try again!') return render(request, 'login.html', {'errors': msg}) @login_required() def registered_users(request): users = User.objects.all() context = { 'users': users } return render(request, 'users.html', context)
Let’s understand the code in this file:
- On line 6 we import the User model that comes with Django authentications system.
- Line 48 to 54 we create a python function called registered_users.
- Line 49 – we retrieve all users using the all() method on object manager.
- Line 51 to 53 – we create a dictionary and pass our users.
- Line 54 – we return a template called users.html which we are yet to create and pass the users to this file.
In the templates create users.html file and make sure it has the following code:
{% extends 'base.html' %} {% block content %} {# top navbar #} {% include 'partials/top_navbar.html' %} {# top navbar #} <div class="container-fluid"> <div class="row"> {# Side navbar #} {% include 'partials/sidenavbar.html' %} {# end of sidenavbar #} <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"><div class="chartjs-size-monitor" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: hidden; pointer-events: none; visibility: hidden; z-index: -1;"><div class="chartjs-size-monitor-expand" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;"><div style="position:absolute;width:1000000px;height:1000000px;left:0;top:0"></div></div><div class="chartjs-size-monitor-shrink" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;"><div style="position:absolute;width:200%;height:200%;left:0; top:0"></div></div></div> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h1 class="h2">Registered Users</h1> </div> {% if messages %} <ul class="messages"> {% for message in messages %} <p class="bg-success" {% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</p> {% endfor %} </ul> {% endif %} <table class="table"> <thead class="thead-dark"> <tr> <th scope="col">Username</th> <th scope="col">Last login</th> <th scope="col">Status</th> <th scope="col">Date joined</th> </tr> </thead> <tbody> {% for user in users %} <tr> <td>{{ user.username }}</td> <td>{{ user.last_login }}</td> <td> {% if user.is_active %} <a href="" class="btn btn-sm btn-danger">Deactivate</a> {% else %} <a href="" class="btn btn-sm btn-success">Activate</a> {% endif % </td> <td>{{ user.date_joined }}</td> </tr> {% endfor %} </tbody> </table> </main> </div> </div> {% endblock %}
Let’s understand the code in this file:
- This file contains just bootstrap classes and nothing more.
- On line 22 to 48 – we create a bootstrap table.
- On line 32 to 45 – we loop through the user’s variable passed to file.
- On line 34 – we display the username
- On line 35 – we display the last login date.
- On line 37 – we check if the user is active.
- On line 38 – if the users is active we display the button to deactivate the user.
- On line 40 – if the user is not active we display the button to activate the user.
- On line 43 – we display which the user registered.
The next step is to create a URL that goes to our registered_users function in the views.py file. Open person_portfolio/urls.py file and make sure it has the following code:
from django.urls import path from . import views urlpatterns = [ path('', views.sign_up, name='user_sign'), path('dashboard', views.user_dashboard, name='user_dashboard'), path('login', views.sign_in, name='login_user'), path('users', views.registered_users, name='system_users'), ]
On line 9, we have created that goes to our function of registered users. This URL has a name called system_users. The next step is to update our sidenavbar.html file. Make sure sidenavbar.html has the following code:
<nav class="col-md-2 d-none d-md-block bg-light sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg> Dashboard <span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg> User profiles </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-shopping-cart"><circle cx="9" cy="21" r="1"></circle><circle cx="20" cy="21" r="1"></circle><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path></svg> Notifications </a> </li> </ul> <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted"> <span>User Management</span> <a class="d-flex align-items-center text-muted" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg> </a> </h6> <ul class="nav flex-column mb-2"> <li class="nav-item"> <a class="nav-link" href="{% url 'system_users' %}"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg> Admins </a> </li> <li class="nav-item"> <a class="nav-link" href="#"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg> Login Audit </a> </li> </ul> </div> </nav>
On line 32 we have updated href parameter to point to our system user URL. Make sure your development server is running and log in to your dashboard, on the dashboard click on Admins on the side navbar. You should see the following screen:
Great work!
Deactivating and Activating the Users
The next step is to implement the ability to deactivate and activate users. Open person_portfolio/views.py file and make sure it has the following code:
from django.shortcuts import render, redirect from django.contrib.auth.forms import UserCreationForm from django.contrib.auth import login, authenticate from django.http import HttpResponse from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.contrib import messages def sign_up(request): if request.method == 'POST': form = UserCreationForm(request.POST) if form.is_valid(): form.save() username = form.cleaned_data.get('username') password = form.cleaned_data.get('password1') user = authenticate(username=username, password=password) login(request, user) return redirect('user_dashboard') else: form = UserCreationForm() return render(request, 'register.html', {'form': form}) @login_required() def user_dashboard(request): return render(request, 'dashboard.html') def sign_in(request): msg = [] if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user) return redirect('user_dashboard') else: msg.append('You account has been deactivated!') else: msg.append('Invalid Login credentials, try again!') return render(request, 'login.html', {'errors': msg}) @login_required() def registered_users(request): users = User.objects.all() context = { 'users': users } return render(request, 'users.html', context) @login_required() def user_deactivate(request, user_id): user = User.objects.get(pk=user_id) user.is_active = False user.save() messages.success(request, "User account has been successfully deactivated!") return redirect('system_users') @login_required() def user_activate(request, user_id): user = User.objects.get(pk=user_id) user.is_active = True user.save() messages.success(request, "User account has been successfully activated!") return redirect('system_users')
Let’s understand the code in this file:
- On line 7 – we import Django messages which help in notifying the user.
- Line 59 – we create a function called user-deactivate which takes the user_id parameter.
- Line 60 – we get an instance of the user whose id is passed to this function.
- Line 61 – we set user is active to false thus they will not be able to log in.
- Line 62 – we update the record in the database.
- Line 63 – we set a success message in the request.
- Line 64 – we redirect to the list of users.
- Line 68 to 73 – we create a function to activate the users. It is exactly the same as user_deactivate function apart from line 70 where we set user is active to true.
The next step is to update our person_portfolio/urls.py file and make sure it has the following code.
from django.urls import path from . import views urlpatterns = [ path('', views.sign_up, name='user_sign'), path('dashboard', views.user_dashboard, name='user_dashboard'), path('login', views.sign_in, name='login_user'), path('users', views.registered_users, name='system_users'), path('activate/user/<int:user_id>', views.user_activate, name='activate_user'), path('deactivate/user/<int:user_id>', views.user_deactivate, name='deactivate_user'), ]
Let’s understand the code in this file:
- Line 10 – we create a URL to activate the user and pass the user id.
- Line 11 – we create a URL to deactivate use and pass the user id.
The next step is to update the users.html and make sure it has the following code:
{% extends 'base.html' %} {% block content %} {# top navbar #} {% include 'partials/top_navbar.html' %} {# top navbar #} <div class="container-fluid"> <div class="row"> {# Side navbar #} {% include 'partials/sidenavbar.html' %} {# end of sidenavbar #} <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4"><div class="chartjs-size-monitor" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: hidden; pointer-events: none; visibility: hidden; z-index: -1;"><div class="chartjs-size-monitor-expand" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;"><div style="position:absolute;width:1000000px;height:1000000px;left:0;top:0"></div></div><div class="chartjs-size-monitor-shrink" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;"><div style="position:absolute;width:200%;height:200%;left:0; top:0"></div></div></div> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h1 class="h2">Registered Users</h1> </div> {% if messages %} <ul class="messages"> {% for message in messages %} <p class="bg-success" {% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</p> {% endfor %} </ul> {% endif %} <table class="table"> <thead class="thead-dark"> <tr> <th scope="col">Username</th> <th scope="col">Last login</th> <th scope="col">Status</th> <th scope="col">Date joined</th> </tr> </thead> <tbody> {% for user in users %} <tr> <td>{{ user.username }}</td> <td>{{ user.last_login }}</td> <td> {% if user.is_active %} <a href="{% url 'deactivate_user' user_id=user.id %}" class="btn btn-sm btn-danger">Deactivate</a> {% else %} <a href="{% url 'activate_user' user_id=user.id %}" class="btn btn-sm btn-success">Activate</a> {% endif %} </td> <td>{{ user.date_joined }}</td> </tr> {% endfor %} </tbody> </table> </main> </div> </div> {% endblock %}
Let’s understand the code in this file:
- Line 21 to 27 – we check if there is the message in the request.
- Line 24 – if there is the message we display the message
- Line 46 – we have updated the href attribute and passed the URL to deactivate the user.
- Line 48 – we have updated the href attribute and passed the URL to activate the user.
That was a lot of work, now let’s test code. Here is a quick test screenshot:
Goal Achieved in this Lesson
- Learned how to query users.
- Learned how to use Django messages.
- Learned how to activate users.
- Learned how to deactivate users
With that, we conclude this lesson. Get the code of this tutorial series.
Facebook Comments