Web3 backend and smart contract development for Python developers part 8: Django backend (login and logout functionality)
ilija
Posted on October 3, 2023
Now we will move to Django backend part. First step as always is to activate proper Python virtual enviroment. From ./musical_nft_thumbnails
folder
$source env/bin/activate
What we need at this point is landing page. Login, logout, sign-up functionality as well as reset password. Ones user sign-up and login into our platform we will redirect him/her to his personal page. There he will be able to see personal information, NFTs he own, buy new with crypto or credit card.
From root folder create new Django app authentication
$py manage.py startapp authentication
In this newly created app we will manage sign-in process, login, logout and reset password.
Add to musical_nft/settings.py
authentication
to list of installed apps:
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# here =>
"authentication",
]
Now in global urls.py
inside musical_nft/settings.py
add
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("authentication.urls"))
]
Now all path
we have inside authentication app will be pluged to this project urls.py
In authentication app folder create another urls.py
and pass following code
from django.urls import path
from .views import HomeView
urlpatterns = [
path("", HomeView.as_view(), name="home"),
]
If you didn't create super user lets do it now
$python manage.py createsuperuser
Now open browser http:127.0.0.1:8000/admin
while local Django server running and type superuser credentials (always make sure your postgres server is up and running $sudo service postgresql start
).
Ones you are logged in go to user and add new user (confirm password)
At this point we need authentication
view class and few html page to be rendered. Have on mind when you create Django apps that it is always 3 step process: defining urls (in app), views (in our case class based view. It can easly be function based view if you like to experiment with alternative implementations of this code) and templates (html page to be rendered with few added Django elements).
Inside views.py
file of authentication
app add following code:
from django.shortcuts import render
from django.views.generic import TemplateView
class HomeView(TemplateView):
def get(self, request):
return render(request, "home.html", {})
Only for test purpose lets make simple home.html
file with message to be displayed in browser. For this to happen create in ./muscial_nft_thumbnails/tempaltes/home.html
{% extends "base.html" %}
{% block content%}
<h1> Test screen </h1>
{% endblock content%}
This peculiar curly brackets above are part Django syntax we need to use with our templates
Then in settings.py
define root of template
folder
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",
],
},
},
]
In this project we will use bootstrap for styling. Go on their documentation page and pick up from introduction
second option number two, Include Bootstrap’s CSS and JS.
and pass that code in newly created base.html
inside project root ./templates
folder (or you can simply copy from here)
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Muscial NFT</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<div class="container ">
<br/>
<br/>
{% block content %}
{% endblock content %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
</body>
</html>
Now add navbar
to our base.hmtl
page.
We can do this again over bootstrap
site documentation, search for navbar
in components
. Choose one you like the most. For our demostration purpose first will be ok.
Here is edited code that you need to pass to navbar.html
file inside ./templates
folder in project root directoy.
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'home' %}">Musical NFT </a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
And then just go to previously created base.html
and add one new line bellow first body tag
{% include "navbar.html"%}
From root directory
$py manage.py runserver
Go to browser to http://127.0.0.1:8000
and check if you get proper message displayed
Now if you go back to you browser you should see somethin like this
Ones we have this we can move and add some basic sign-in, login, logout and reset password functionality. For login and logout we will use Django authentication system.
Here is general overview on how we plan to plug all things together related to authetication
First we will further develop 3 basic templates: navbar
, base
and home
(base
includes navbar
and home
extends base
as flow shows). We should have on mind that home
will have two possbilities: 1) if user is logged we will show to him his personal page; 2) If user is not logged we will offer him login forms (you can check this in home.html
).
navbar.html
(modified bootstrap navbar)
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'home' %}">Musical NFT </a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
{% if user.is_authenticated%}
<li class="nav-item">
<a class="nav-link" href="{% url 'logout'%}">Logout</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'home'%}">Login</a>
</li>
{% endif%}
</ul>
</li>
</ul>
</div>
</div>
</nav>
Now base.html
to include navbar.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Muscial NFT</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
{% include "navbar.html"%}
<div class="container ">
<br/>
<br/>
{% if messages %}
{% for message in messages%}
<div class="alert alert-warning alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor%}
{% endif %}
{% block content %}
{% endblock content %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
</body>
</html>
Here I want to draw your attention on last {% block content %}
{% endblock content %}
This is place where base.html
injects any other template that inheriti from him with extends
command (in our case home.html
)
Then few lines above you have a bit strange syntax with {% if messages %} {% for message in messages%}
Simply this is the way we pass to our template success error message. You will find more details about this in view.py
.
As we see home.html
will extend base.html
and have inside itself Django specific if/else
statemnt. This if/else
statment will help us check if user is logged in, then we will offer to him his persoanl page. In case he is not logged in we will show login form.
Here is code example:
{% extends "base.html" %}
{% block content%}
<div class="col-md-6 offset-md-3">
{% if user.is_authenticated %}
<h1> Welcome <h1/>
{% else %}
<h1> Login </h1>
<br/>
<form method="POST" action="{% url 'home' %}">
{% csrf_token %}
<form>
<div class="mb-3">
<input type="text" class="form-control" aria-describedby="emailHelp" placeholder="Username" name="username" required>
</div>
<div class="mb-3">
<input type="password" class="form-control" placeholder="Password" name="password" required>
</div>
<button type="submit" class="btn btn-secondary">Submit</button>
</form>
</form>
</div>
{% endif %}
{% endblock content%}
Now we have all templates and we can finally move to authentication app folder where we need to update our urls.py
with following code
from django.urls import path
from .views import HomeView, LogoutUser
urlpatterns = [
path("", HomeView.as_view(), name="home"),
# path("login/", LoginUser.as_view(), name="login"),
path("logout/", LogoutUser.as_view(), name="logout"),
]
As you can see we added new logout path (login is part of normal home
path and HomeView
class) which will be handled with LogoutUser
class inside authenticaiotn view.py
As you may guess last piece of puzzle we need now is view
handler which will glue all this elements together. Here is example of possbile code:
from django.shortcuts import render, redirect
from django.views.generic import TemplateView
from django.contrib.auth import authenticate, login, logout
from django.contrib import messages
class HomeView(TemplateView):
template_name="home.html"
def post(self, request):
# check to see if loggin in
user_name = request.POST["username"]
password = request.POST["password"]
user = authenticate(request, username=user_name, password=password)
if user is not None:
login(request, user)
messages.success(request, "You have been logged in!")
return redirect("home")
else:
messages.success(request, "There was An Error login in, please try again")
return redirect("home")
def get(self, request):
return render(request, "home.html", {})
class LogoutUser(TemplateView):
def get(self, request):
logout(request)
messages.success(request, "You have been logged out!")
return redirect("home")
In this moment run your Django server locally (be sure again your postgres server is up and runnig) and then go to http://127.0.0.1:8000
If you are logged out as admin, you should see something like this
Now type admin or newly created user credentials and you should see something like this =>
Look at upper left corner of navbar
logout button. This button will hit our logout/
path and then LogoutUser
class handler (from views.py
) which will then simply logout current user and redirect him to home
page.
And on this point finally we can see very nice moment in home.html
. This loop inside home.html
will see that user is not logged in any more and he will show him login format. And basically with this nice detail we have everything in one place: login, logout and user profile all nicely connected thorough this template loop.
Now when we have login
and logout
let's move to develop sign-up
and reset password
functionality before we start to work on our web3 integration.
Code for this you can find on github
Posted on October 3, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.