Django #1

We >>wstępie<< opisałem główne założenia projektu.

Poniżej zamieszczam listing wymaganych pakietów do projektu (wygenerowany przez pip freeze):

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

Polecam utworzyć osobne środowisko wirtualne dla projektu (jak stworzyć wirtualne środowisko opisałem >>tutaj<<).

Wszystkie pakiety oprócz django-crispy-forms instalowane są podczas instalacji pakietu django.

W katalogu zawierającym również podkatalog venv tworzymy projekt za pomocą komendy: django-admin startproject nazwa_projektu

Startproject tworzy główny katalog projektu oraz plik manage.py, dzięki któremu można będzie zarządzać projektem.

Następnie można utworzyć administratora projektu, czyli użytkownika o maksymalnych uprawnieniach administracyjnych, dzięki czemu będzie można używać webowego panelu administracyjnego. Jednak najpierw należy przeprowadzić migracje: python manage.py migrate dzięki czemu zostają utworzone odpowiednie tabele w bazie danych np. admin, auth itd. Po przeprowadzonej migracji można utworzyć konto administracyjne za pomocą komendy: python manage.py createsuperuser

Katalog projektu zawiera następujące pliki i katalogi:
├── nazwa_projektu
│   ├── asgi.py
│   ├── init.py
│   ├── pycache
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
└── manage.py

Domyślnie dane umieszczane zostają w bazie sqlite3 (standardowo plik db.sqlite3), co jest dobrym rozwiązaniem podczas tworzenia projektu, a finalnie można użyć innej bazy (Django zawiera wsparcie dla PostgreSQL, MySQL i wielu innych). Zmiana domyślnej bazy wymaga tylko modyfikacji danych z sekcji DATABASES pliku settings.py projektu.

Aby odseparować poszczególne elementy składowe projektu wydzieliłem dwie części składowe tzn. odpowiedzialną za zarządzanie użytkownikami – users oraz za zarządzanie pojazdami – cars. W Django są to tzw. aplikacje. Aby je utworzyć należy wpisać: python manage.py startapp users oraz python manage.py startapp cars

Zacznę od aplikacji users, w której nowi użytkownicy będą mogli tworzyć konta, oraz logować się, wylogowywać, a także zmieniać swoje hasło dostępowe.

Aby określić mapowanie adresów URL na konkretne klasy widoków modyfikuję plik urls.py projektu tzn.

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'),
]

Przykładowo po wpisaniu adresu kończącego się na: register-user/ zostaje wywołana klasa RegisterUser() z pliku views.py oraz do tego przypisania zostaje nadana nazwa, której będziemy mogli używać w szablonach. Aby klasa mogła być użyta jako widok, należy wywołać jej metodę as_view(). Jako argument podałem argument template_name, w którym podaję nazwę szablonu, który wyświetla podaną stronę. Równie dobrze można by podać ten argument jako atrybut klasy w widoku, ale aby zachować spójność z pozostałymi widokami umieściłem go w tym miejscu.

kod klasy RegisterUser() z pliku views.py aplikacji users wygląda następująco (na początku umieściłem wymagane importy)

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

Klasa RegisterUser() dziedziczy po klasie CreateView, a formularz jest definiowany przez klasę UserCreationForm. Gdy strona zostaje wyświetlona za pomocą metody GET to pojawia się pusty formularz, gdy natomiast podane są już jakieś dane w formularzu, to są one przekazane za pomocą metody POST. Aby obsłużyć GET i POST przesłaniam odpowiednio metody get() i post() klasy RegisterUser(). W metodzie post() sprawdzana jest poprawność formularza i jeśli formularz jest poprawny to następuje zapisanie danych z formularza tzn. utworzenie użytkownika za pomocą metody save(). Domyślnie jest to użytkownik pozbawiony przywilejów administracyjnych. Zostaje on zalogowany przy użyciu podanych przy rejestracji danych. Nowa wiadomość z tagiem Success zostanie wyświetlona po przekierowaniu na adres o nazwie cars. Wiadomość wyświetla się tylko jednokrotnie na stronie.

Pozostaje jeszcze utworzyć szablon register-user.html dla RegisterUser(). W tym celu tworzę katalog szablonów w aplikacji users zgodnie z konwencją – w katalogu templates należy utworzyć kolejny katalog z nazwą zgodną z nazwą aplikacji tzn.

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

Kod pliku register-user.html jest częścią większej całości, a ściślej nie utworzonego na razie pliku base.html z aplikacji cars. Aplikacje mogą korzystać ze swoich szablonów, a dzięki temu wygląd zdefiniowany w aplikacji cars w szablonie base.html jest zachowany w szablonie register-user. W szablonie jest też włączone korzystanie z tagów crispy_forms, dzięki którym formularz wygląda lepiej. Każdy formularz musi zawierać csrf_token, dzięki czemu strona jest automatycznie odporna na pewne formy ataków (szczegóły >>tutaj<<).

Listing pliku register-user.html wygląda następująco:

{% 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 %}
Szablon register-user.html

>>część 2<<

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *