DEV Community

ilija
ilija

Posted on • Updated on

Web3 backend and smart contract development for Python developers part 8: Django backend (login and logout functionality)

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
Enter fullscreen mode Exit fullscreen mode

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",
]
Enter fullscreen mode Exit fullscreen mode

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"))
    ]
Enter fullscreen mode Exit fullscreen mode

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"),
    ]
Enter fullscreen mode Exit fullscreen mode

If you didn't create super user lets do it now

$python manage.py createsuperuser
Enter fullscreen mode Exit fullscreen mode

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).

Image description

Ones you are logged in go to user and add new user (confirm password)

Image description

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", {})
Enter fullscreen mode Exit fullscreen mode

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%}
Enter fullscreen mode Exit fullscreen mode

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",
                ],
            },
        },
    ]
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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

Image description

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

Image description

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>

Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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 extendscommand (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%}

Enter fullscreen mode Exit fullscreen mode

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"),
    ]
Enter fullscreen mode Exit fullscreen mode

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")  

Enter fullscreen mode Exit fullscreen mode

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

Image description

Now type admin or newly created user credentials and you should see something like this =>

Image description

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.

Image description

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

Top comments (0)