Django #1

Below is a listing of the required packages for the project:

asgiref==3.2.5
Django==3.0.4
django-crispy-forms==1.9.0
pytz==2019.3
sqlparse==0.3.1

I recommend creating a separate virtual environment for the project (how to create a virtual environment I described here).

All packages except django-crispy-forms are installed when the django package is installed.

In the directory containing the venv subdirectory, create a project with the command: django-admin startproject project_name

Startproject command creates the project’s main directory and a manage.py file for managing the project.

You can then create a project administrator, i.e. a user with maximum administrative privileges, so that you can use the web admin panel. However, first you need to run a migrate: python manage.py migrate thanks to which the appropriate tables are created in the database, e.g. admin, auth etc.

After migration, you can create an administrative account with the command: python manage.py createsuperuser

The project directory contains the following files and directories:

├── project_name
│ ├── asgi.py
│ ├── init.py
│ ├── pycache
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── db.sqlite3
└── manage.py

By default, the data is placed in the sqlite3 database (db.sqlite3 file), which is a good solution when creating a project, and finally you can use a different database (Django includes support for PostgreSQL, MySQL and many others). Changing the default database only requires modifying the data from the DATABASES section of the project’s settings.py file.

In order to separate the individual components of the project, I made two components, i.e. users – responsible for user management and cars for vehicle management. In Django, these are called apps. To create them, type: python manage.py startapp users and python manage.py startapp cars

I will start with the users application, in which new users will be able to create accounts, log in, log out, and change their access password.

To define URL mapping to specific view classes, I modify the project urls.py file, i.e.

from django.contrib import admin
from django.urls import path
from users import views as users_views
from django.contrib.auth import views as auth_views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('register-user/', users_views.RegisterUser.as_view(
        template_name='users/register-user.html'), name='register_user'),
    path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
    path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name='logout'),
    path('change-password/', users_views.ChangePassword.as_view(
        template_name='users/change-password.html'), name='change_password'),
]

For example, after entering the address ending with: register-user /, the class RegisterUser () is called from the views.py file and the assignment is given a name that we can use in templates.

For a class to be used as a view, its as_view () method must be called. As an argument I have given the template_name argument, in which I give the name of the template that displays the given page. You might as well pass this argument as a class attribute in a view, but for consistency with the rest of the views, I have included it here.

The code of the RegisterUser () class from the views.py file of the users application looks as follows (at the beginning I put the required imports):

from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm, PasswordChangeForm
from django.contrib.auth import login, authenticate
from django.views.generic import CreateView
from django.contrib import messages

class RegisterUser(CreateView):
    form_class = UserCreationForm

    def get(self, request, *args, **kwargs):
        return render(request, 'users/register-user.html', {'form': UserCreationForm()})

    def post(self, request, *args, **kwargs):
        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)
            messages.success(request, f'Welcome, {username}!')
            return redirect('cars')
        return render(request, 'users/register-user.html', {'form': form})

The RegisterUser () class inherits from the CreateView class, and the form is defined by the UserCreationForm class.

When the page is displayed using the GET method, an empty form appears, while if some data is already provided in the form, it is passed using the POST method.

To handle GET and POST, I override the get() and post() methods of RegisterUser(), respectively. In the post() method, the form is validated and if the form is correct, then the data from the form is saved, ie the user is created using the save() method. By default, this is a user with no administrative privileges. He is logged in using the data provided during registration. A new message with the tag Success will be displayed after redirecting to an address named cars. The message is displayed only once.

It remains to create the register-user.html template for RegisterUser(). For this purpose, I create a template directory in the users application according to the convention – in the templates directory, create another directory with the name consistent with the name of the application, i.e.

project_name/users/templates/users/register-user.html

The code of register-user.html is part of a larger whole, or more precisely, the base.html file from the cars application, which has not been created yet.

Applications can use their templates, so the look defined in cars in base.html is preserved in register-user.html

The template also enables the use of crispy_forms tags to make the form look better.

Each form must contain csrf_token, thanks to which the website is automatically immune to some forms of attacks (details: here).

Code of register-user.html file:

{% extends 'cars/base.html' %}
{% load crispy_forms_tags %}

{% block content %}
  <div class="row justify-content-center">
    <div class="col-4">
      <form method="POST" class="form-control-sm">
        {% csrf_token %}
        <fieldset class="form-group">
          <legend class="border-bottom text-primary">
            Registration
          </legend>
            {{ form|crispy }}
        </fieldset>
          <button class="btn btn-secondary" type="submit">Register</button>
      </form>
    </div>
  </div>
{% endblock %}

One thought on “Django #1”

Leave a Reply

Your email address will not be published. Required fields are marked *