Recherche de site Web

Créez un journal personnel avec Django et Python


Un journal est un espace de sécurité personnel. Avec l'aide de Django, vous pouvez créer un journal sur votre propre ordinateur sans stocker de données dans le cloud de quelqu'un d'autre. En suivant le projet ci-dessous, vous verrez à quelle vitesse vous pouvez créer une application Web fonctionnelle dans Django sans aucune dépendance externe.

Dans ce didacticiel, vous apprendrez à :

  • Mettre en place un projet Django
  • Travailler avec la base de données SQLite standard
  • Utilisez le site d'administration de Django
  • Créer des modèles et des vues basées sur les classes
  • Modèles d'imbrication et de style
  • Sécurisez votre agenda avec authentification

Ce didacticiel vous guidera étape par étape jusqu'à votre agenda final. Si vous débutez avec Django et souhaitez terminer votre premier vrai projet, alors ce tutoriel est fait pour vous !

Pour obtenir le code source complet du projet Django et ses étapes, cliquez sur le lien ci-dessous :

Vidéo de démonstration

Sur la page principale de votre agenda, vous aurez une liste d’entrées. Vous pouvez les faire défiler et en créer de nouveaux en un seul clic. Le style est fourni dans ce tutoriel, vous pouvez donc vous concentrer sur la partie Django du code. Voici une rapide vidéo de démonstration de ce à quoi cela ressemblera en action :

À la fin du didacticiel, vous serez en mesure de naviguer parfaitement dans votre agenda pour créer, lire, mettre à jour et supprimer des entrées à la demande.

Aperçu du projet

Le didacticiel est divisé en plusieurs étapes. De cette façon, vous pourrez faire des pauses et continuer à votre rythme. À chaque étape, vous aborderez un domaine spécifique de votre projet de journal :

  1. Configurer votre projet de journal Django
  2. Création d'entrées sur le back-end
  3. Afficher les entrées sur le front-end
  4. Ajout de style
  5. Gestion des entrées sur le front-end
  6. Améliorer votre expérience utilisateur
  7. Implémentation de l'authentification

En suivant, vous explorerez les bases des applications Web et comment ajouter des fonctionnalités communes à un projet Django. Après avoir terminé le didacticiel, vous aurez créé votre propre application de journal personnel et disposerez d'un plan de projet Django sur lequel vous appuyer.

Conditions préalables

Vous n’avez besoin d’aucune connaissance préalable de Django pour mener à bien ce projet. Si vous souhaitez en savoir plus sur les sujets abordés dans ce didacticiel, vous trouverez des liens vers des ressources tout au long du parcours.

Cependant, vous devez être à l'aise avec la ligne de commande et avoir une connaissance de base de Python et des classes. Bien qu'il soit utile de connaître les environnements virtuels et pip, vous apprendrez à tout configurer au cours de ce didacticiel.

Étape 1 : Configuration de votre journal Django

Démarrez le projet en créant votre répertoire de projet et en configurant un environnement virtuel. Cette configuration gardera votre code isolé de tout autre projet sur votre machine. Vous pouvez nommer votre dossier de projet et l'environnement virtuel comme vous le souhaitez. Dans ce didacticiel, le dossier du projet est nommé my-diary et l'environnement virtuel est nommé .venv :

$ mkdir my-diary
$ cd my-diary
$ python3 -m venv .venv
$ source .venv/bin/activate

Votre invite commence maintenant par le nom de votre environnement virtuel entre parenthèses. Ceci est un indicateur que l'environnement virtuel est activé. Pour la suite du tutoriel, votre environnement virtuel doit être activé. Toutes les étapes suivantes se dérouleront dans ce répertoire ou ses sous-répertoires.

c:\> python -m venv .venv
c:\> .venv\Scripts\activate.bat

Pour d’autres plates-formes et shells, vous devrez peut-être utiliser une commande différente.

La seule autre exigence pour votre journal est Django lui-même. Installez la version spécifique de ce tutoriel avec pip :

(.venv) $ python -m pip install Django==3.2.1

Cette commande installe Django et certaines dépendances requises par Django. C'est tout ce dont vous avez besoin.

Initialiser Django

Une fois toutes les conditions requises remplies, il est temps de démarrer le projet Django lui-même. Utilisez l'utilitaire de ligne de commande de Django pour créer la structure de base du projet :

(.venv) $ django-admin startproject diary .

N'oubliez pas d'ajouter le point (.) à la fin de la commande ci-dessus. Le point empêche Django de créer un autre répertoire pour votre projet de journal.

Django vient de créer un fichier manage.py et un dossier nommé diary avec cinq fichiers. Vous n’êtes pas obligé de comprendre ce qu’ils font précisément. Si vous êtes curieux, vous pouvez jeter un œil aux fichiers. Ils contiennent tous au début une explication décrivant pourquoi ils existent. Au cours de ce didacticiel, vous n’aurez besoin d’en modifier que deux :

manage.py

diary/__init__.py

diary/asgi.py

diary/settings.py

diary/urls.py

diary/wsgi.py

Désormais, le fichier manage.py prendra en charge les tâches administratives en ligne de commande. Vous en rencontrerez quelques-uns au cours de ce tutoriel.

Créer la base de données

Maintenant que les bases de votre projet de journal Django sont préparées, vous avez besoin d'un emplacement pour stocker le futur contenu de votre journal. Pour cela, vous devez créer une base de données.

Django est livré avec la prise en charge de plusieurs bases de données et fonctionne par défaut avec une base de données SQLite si aucune autre configuration de base de données n'est fournie. Une base de données SQLite est tout ce dont vous avez besoin car vous êtes le seul utilisateur à s'y connecter et votre projet de journal Django ne s'exécutera que localement.

La meilleure partie est que vous pouvez créer une base de données SQLite avec une seule commande. En exécutant des migrations, vous appliquez les modifications d'un schéma de base de données dans la base de données :

(.venv) $ python manage.py migrate

Lorsque vous regardez dans le répertoire de votre projet, vous devriez voir un fichier db.sqlite3. Donnez-vous une tape sur l'épaule : vous venez de créer une base de données !

Pour comparer l'état actuel de votre projet avec les fichiers téléchargeables pour ce didacticiel, cliquez sur le lien ci-dessous :

Les fichiers liés à cette section se trouvent dans le répertoire source_code_step_1/.

Soyez un superutilisateur

En tant que propriétaire de votre journal personnel, vous avez mérité le rôle de superutilisateur. Réclamez-le avec cette commande :

(.venv) $ python manage.py createsuperuser
Username (leave blank to use 'root'): admin
Email address: admin@example.com
Password: RealPyth0n
Password (again): RealPyth0n
Superuser created successfully.

Vous serez invité à choisir un nom d'utilisateur, à fournir une adresse e-mail et à définir un mot de passe. C'est la clé de votre journal, alors assurez-vous de vous en souvenir.

Exécuter un serveur Web de développement

Une autre commande que vous utiliserez fréquemment est runserver. Cette commande exécute un serveur Web de développement léger :

(.venv) $ python manage.py runserver

Vous pouvez spécifier l'adresse IP et le port de runserver. Par défaut, le serveur s'exécute sur le port 8000 sur 127.0.0.1 et n'est accessible que sur votre ordinateur. Avec le serveur en cours d'exécution, vous pouvez visiter votre projet Django dans votre navigateur en utilisant soit http://127.0.0.1:8000 ou http://localhost:8000 :

Ceci est la page d'accueil de votre agenda. Pour l’instant, il n’y a qu’une fusée à voir. Cela signifie que l'installation a réussi.

Terminez la première étape de ce didacticiel en visitant http://localhost:8000/admin et en vous connectant avec vos informations d'identification :

Ceci est votre propre site d'administration Django ! C'est l'une des fonctionnalités les plus puissantes de Django. Avec seulement quelques ajustements, il vous donne la possibilité de gérer immédiatement le contenu et les utilisateurs. Pour l’instant, il n’y a pas grand chose à voir sur le site d’administration de Django. Il est temps de changer ça !

Étape 2 : Ajout de vos entrées de journal au back-end

Un projet Django contient une ou plusieurs applications. La portée d'une application doit être limitée. Au début, faire la différence entre un projet et des applications peut prêter à confusion. Mais dans les grands projets Django, cette séparation des préoccupations maintient la base de code propre. Un autre avantage de cette structure est que vous pouvez réutiliser des applications pour d'autres projets.

Connectez l'application Entrées

Dans votre terminal, le serveur web de développement Django est peut-être toujours en cours d'exécution. Arrêtez-le en appuyant sur Ctrl<span>+C dans le terminal.

Dans ce didacticiel, vous n'avez besoin que d'une seule application supplémentaire. L'objectif principal de cette application est de gérer les entrées de votre journal, appelons donc l'application entrées. Exécutez la commande pour créer l'application entries :

(.venv) $ python manage.py startapp entries

Cette commande crée un dossier entries dans votre projet avec quelques fichiers prédéfinis. Vous n’aurez besoin d’en modifier que trois plus tard dans ce didacticiel :

entries/__init__.py

entries/admin.py

entries/apps.py

entries/models.py

entries/tests.py

entries/views.py

Comme vous pouvez le constater, certains d'entre eux portent le même nom que les fichiers du répertoire diary/. En cliquant sur le lien ci-dessous, vous pouvez comparer votre structure de dossiers avec celle du répertoire source_code_step_2/ :

Jusqu'à présent, Django ne connaît pas l'application que vous venez de créer. Pour connecter l'application entries au projet de journal Django, ajoutez le chemin d'accès à la classe de configuration au début de la liste INSTALLED_APPS dans journal/settings.py :

# diary/settings.py

INSTALLED_APPS = [
  "entries.apps.EntriesConfig",
  "django.contrib.admin",
  "django.contrib.auth",
  "django.contrib.contenttypes",
  "django.contrib.sessions",
  "django.contrib.messages",
  "django.contrib.staticfiles",
]

L'application entries est désormais connectée au projet diary et Django trouve ses configurations. L'une de ces configurations est le modèle qui décrit à quoi doivent ressembler vos entrées de journal dans la base de données.

Créer le modèle d'entrées

Vous avez déjà créé la base de données. Il est maintenant temps de définir la table de base de données où seront stockées les entrées de votre journal. Dans Django, vous faites cela avec une classe modèle. Tout comme les classes conventionnelles en Python, les noms de modèles doivent être au singulier et en majuscules. Alors que votre application s'appelle entries, votre modèle s'appellera Entry.

Les champs du modèle Entry sont les éléments que contiendra une entrée de journal. Au premier plan, ces champs seront affichés sous forme de formulaire. Au fond, ce seront les colonnes de votre table de base de données Entry. Une entrée de journal dans ce didacticiel contient trois champs :

  1. titre est le titre.
  2. content est le corps principal du texte.
  3. date_created est la date et l'heure de création.

Dans entries/models.py, importez d'abord le timezone depuis django.utils. Créez ensuite la classe Entry dans le même fichier comme indiqué ci-dessous :

# entries/models.py

from django.db import models
from django.utils import timezone

class Entry(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    date_created = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.title

    class Meta:
        verbose_name_plural = "Entries"

En important le module timezone, vous pouvez utiliser timezone.now comme argument default pour date_created à la ligne 9. De cette façon, la date et l'heure actuelles seront utilisées par défaut si vous ne leur définissez pas de valeur spécifique lors de la création d'une entrée. Vous utiliserez ce comportement plus tard lorsque vous créerez un formulaire pour vos entrées de journal.

En plus de title, content et date_created, Django ajoutera automatiquement id comme élément principal unique clé. La représentation sous forme de chaîne d'une entrée avec la clé primaire 1 serait Entry object (1) par défaut. Lorsque vous ajoutez .__str__(), vous pouvez personnaliser ce qui est affiché à la place. Pour une entrée de journal, le titre est une meilleure représentation sous forme de chaîne.

Une autre variable que vous devez ajuster est verbose_name_plural. Sinon, Django épellerait le pluriel de votre Entry comme Entrys et non Entries.

Enregistrez le modèle d'entrée

Pour voir également le modèle Entry dans le site d'administration de Django, vous devez l'enregistrer dans entries/admin.py :

# entries/admin.py

from django.contrib import admin
from .models import Entry

admin.site.register(Entry)

Django ne générera pas d'erreur lorsque vous oubliez d'enregistrer un modèle sur le site d'administration. Après tout, tous les modèles ne doivent pas nécessairement être gérés dans une interface utilisateur. Mais pour le produit minimal viable de votre agenda, vous profiterez du site d'administration Django intégré.

Migrer le modèle d'entrée

Après avoir ajouté la nouvelle classe et l'avoir enregistrée sur le site d'administration, vous devez créer des fichiers de migration pour Django et les exécuter. Avec makemigrations, vous créez les fichiers de migration, qui contiennent les instructions de Django pour construire une base de données. Avec migrate, vous les implémentez :

(.venv) $ python manage.py makemigrations
(.venv) $ python manage.py migrate

Une fois les migrations terminées, exécutez le serveur Web de développement, accédez au navigateur et visitez le site d'administration de Django à l'adresse http://localhost:8000/admin :

Actuellement, aucune entrée n’est répertoriée. Terminez cette étape en créant au moins une entrée dans votre journal en cliquant sur Ajouter une entrée. Pas sûr de savoir quoi écrire? Réfléchissez peut-être à quel point il est génial d'avoir un back-end entièrement fonctionnel pour votre projet de journal Django !

Étape 3 : Affichage de vos entrées de journal sur le front-end

Vous pouvez désormais ajouter de nouvelles entrées dans le site d'administration de Django. Mais lorsque vous visitez la page d'accueil de votre journal dans le navigateur, la fusée tremblante s'affiche toujours. Dans cette étape, vous apprendrez comment afficher les entrées de votre journal sur le front-end.

Si vous souhaitez voir à quoi ressemble le code à la fin de cette étape, cliquez sur le lien ci-dessous :

Les fichiers liés à cette étape se trouvent dans le répertoire source_code_step_3/.

Créer des vues de liste et de détail

Il existe deux types de vues dans Django : les vues basées sur les fonctions et les vues basées sur les classes. Les deux acceptent une requête Web et renvoient une réponse Web. De manière générale, les vues basées sur les fonctions vous offrent plus de contrôle mais aussi plus de travail. Les vues basées sur les classes vous offrent moins de contrôle mais aussi moins de travail.

Moins de travail, ça semble bien. Mais ce n’est pas la seule raison pour laquelle vous utiliserez des vues basées sur les classes pour votre journal. Votre journal Django utilisera des vues typiques d'une application Web, comme l'affichage d'une liste d'éléments de base de données ou de leurs détails. C’est pourquoi les vues basées sur les classes constituent un bon choix pour les vues de votre journal.

Django fournit de nombreuses vues génériques prêtes à l'emploi. Dans ce cas, vous allez créer des sous-classes d'un DetailView et d'un ListView et les connecter à votre modèle Entry dans entries/views.py :

# entries/views.py

from django.views.generic import (
    ListView,
    DetailView,
)

from .models import Entry

class EntryListView(ListView):
    model = Entry
    queryset = Entry.objects.all().order_by("-date_created")

class EntryDetailView(DetailView):
    model = Entry

Comme promis, vous n’avez pas beaucoup de code à écrire pour le moment. La requête Entry.objects.all() à la ligne 12 renverrait toutes les entrées classées par leur clé primaire. L'améliorer avec .order_by("-date_created") renverra vos entrées par ordre croissant, avec l'entrée la plus récente en haut de la liste.

Lorsque vous écrivez une vue comme celle-ci, Django fera des hypothèses en arrière-plan, telles que le nom et l'emplacement du modèle à restituer par la vue.

Créez vos modèles

Avec les modèles, vous pouvez générer du HTML de manière dynamique. Django s'attend à ce que les modèles des vues basées sur les classes que vous venez de créer se trouvent dans un emplacement spécifique avec un nom particulier. Créez les sous-dossiers pour vos modèles :

(.venv) $ mkdir -p entries/templates/entries

Certes, le chemin vers les modèles semble un peu étrange. Mais de cette façon, vous vous assurez que Django trouvera exactement les bons modèles, même lorsque d'autres applications partagent les mêmes noms de modèles. À l'intérieur de entries/templates/entries/, vous stockerez tous les fichiers modèles pour le modèle Entry. Commencez par créer entry_list.html et ajoutez ce contenu :

<!-- entries/templates/entries/entry_list.html -->

{% for entry in entry_list %}
    <article>
        <h2 class="{{ entry.date_created|date:'l' }}">
            {{ entry.date_created|date:'Y-m-d H:i' }}
        </h2>
        <h3>
            <a href="{% url 'entry-detail' entry.id %}">
                {{ entry.title }}
            </a>
        </h3>
    </article>
{% endfor %}

Dans les modèles Django, vous pouvez même référencer dynamiquement des classes CSS. Lorsque vous jetez un œil à <h2> à la ligne 5, vous pouvez voir que class="{{ Entry.date_created|date:'l' }}" est ajouté à cela. Cela montre l'horodatage avec un formatage spécial. De cette façon, l'élément <h2> a le jour de la semaine comme classe, et vous pourrez ultérieurement attribuer à chaque jour de la semaine une couleur unique dans le CSS.

À l'intérieur de la boucle entry_list, vous pouvez accéder aux champs du modèle Entry. Pour ne pas encombrer la liste avec trop d'informations, vous n'afficherez le contenu que lorsque vous visiterez la page de détail d'une entrée. Créez cette page de détails dans entries/templates/entries/ avec entry_detail.html comme nom de fichier et ajoutez ce contenu :

<!-- entries/templates/entries/entry_detail.html -->

<article>
    <h2>{{ entry.date_created|date:'Y-m-d H:i' }}</h2>
    <h3>{{ entry.title }}</h3>
    <p>{{ entry.content }}</p>
</article>

Un modèle detail attend exactement un objet d'entrée. C’est pourquoi vous pouvez y accéder directement ici sans boucle.

Ajouter des itinéraires à vos vues

Pour voir les modèles en action, vous devez connecter vos vues à des URL. Django fonctionne avec un fichier urls.py pour répartir les requêtes entrantes des utilisateurs dans le navigateur. Un fichier comme celui-ci existe déjà dans le dossier du projet diary. Pour l'application d'entrées, vous devez d'abord la créer dans entries/urls.py et ajouter les chemins vers EntryListView et EntryDetailView :

# entries/urls.py

from django.urls import path

from . import views

urlpatterns = [
    path(
        "",
        views.EntryListView.as_view(),
        name="entry-list"
    ),
    path(
        "entry/<int:pk>",
        views.EntryDetailView.as_view(),
        name="entry-detail"
    ),
]

La fonction path() aux lignes 8 et 13 doit avoir au moins deux arguments :

  1. Un modèle de chaîne route, qui contient un modèle d'URL
  2. La référence à une vue, qui est une fonction as_view() pour les vues basées sur les classes

De plus, vous pouvez transmettre des arguments en tant que kwargs et fournir un nom. Avec un nom, vous pouvez facilement référencer des vues dans votre projet Django. Ainsi, même si vous décidez de modifier le modèle d’URL, vous n’avez pas besoin de mettre à jour vos modèles.

Maintenant que les URL de l'application entries sont en place, vous devez les connecter à la liste urlpatterns de agenda. Lorsque vous ouvrez diary/urls.py, vous verrez les urlpatterns utilisés par votre projet Django Diary. Jusqu'à présent, il n'y a que la route vers "admin/", qui est ajoutée par défaut pour que vous puissiez accéder au site d'administration de Django. Pour afficher les entrées de votre journal lorsque vous visitez http://localhost:8000, vous devez d'abord envoyer l'URL racine à l'application entries :

# diary/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("entries.urls")),
]

Après avoir créé de nouveaux modèles, redémarrez manuellement le serveur Web de développement Django. Ensuite, visitez http://localhost:8000 et profitez de votre point de vue :

Vous pouvez voir les détails d'une entrée en cliquant sur le lien vers celle-ci dans la liste ou en visitant http://localhost:8000/entries/1, où 1 est le ID d'une entrée existante.

Désormais, tout est en place pour voir vos entrées en front-end. Cependant, votre journal semble toujours un peu démodé. Changeons cela à l’étape suivante !

Étape 4 : Rendre votre journal Django joli

Dans cette étape, vous ajouterez du style à votre agenda. Si vous souhaitez jeter un œil au code terminé de cette étape, cliquez sur le lien ci-dessous et consultez le répertoire source_code_step_4/ :

Bien que votre écriture soit créative, la conception du journal est actuellement un peu basique. Vous pouvez commencer à pimenter les choses en créant un modèle de base dans entries/templates/entries/base.html avec ce contenu :

<!-- entries/templates/entries/base.html -->

{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>My Diary</title>
    <link rel="stylesheet" href="{% static 'css/diary.css' %}">
</head>

<body>
    <h1><a href="/">Dear diary …</a></h1>

    {% block content %}{% endblock %}

</body>

</html>

Avec l’héritage de modèles, vous n’avez pas besoin de répéter le balisage dans vos modèles. Au lieu de cela, vous étendez vos modèles enfants. Django les fusionne ensuite automatiquement lors de leur diffusion dans la vue.

Ajouter une feuille de style

En insérant {% load static %} au début d'un fichier modèle, vous pouvez référencer des fichiers statiques avec le modèle {% static %} balise et un chemin relatif vers le fichier CSS. Créez diary.css dans entries/static/css/ et développez la case ci-dessous pour afficher le code CSS que vous ajouterez au fichier.

Copiez et collez le code CSS ci-dessous dans diary.css :

/* entries/static/css/diary.css */

* {
    box-sizing: border-box;
}

body {
    font-family: sans-serif;
    font-size: 18px;
}

a {
    color: inherit;
}
a:hover {
    opacity: 0.7;
}

h1 {
    font-size: 2.8em;
}

h1 a {
    text-decoration: none;
}

h2, h3 {
    font-size: 1.4em;
    margin: 0;
    display: inline-block;
    padding: 0.5rem 1rem;
    vertical-align: top;
}

h2 {
    background-color: aquamarine;
}

.mark {
    background-color: gainsboro;
}
.mark a {
    text-decoration: none;
}

article {
    margin-bottom: 0.5rem;
}

p {
    font-size: 1.2em;
    padding-left: 1rem;
    line-height: 1.3em;
    max-width: 36rem;
    color: dimgray;
}

em {
    font-style: normal;
    font-weight: bold;
}

/* Form */

label {
    display: block;
}

button,
textarea,
input {
    font-size: inherit;
    min-height: 2.5em;
    padding: 0 1rem;
}

input[type="text"],
textarea {
    width: 100%;
}

textarea {
    padding: 0.5rem 1rem;
    font-family: sans-serif;
}

button,
input[type="submit"] {
    margin: 0 1rem 2px 1rem;
    cursor: pointer;
    font-weight: bold;
    min-width: 8rem;
}

/* Day coloring */

.Saturday,
.Sunday {
    background-color: lightsalmon;
}

N'hésitez pas à améliorer et optimiser le code ci-dessus pour ajuster les éléments à votre goût. Si vous ne connaissez pas CSS, cela vaut la peine d’apprendre les bases si vous aimez le développement Web.

Comme indiqué précédemment, chaque élément <h2> de la liste d'entrées a son jour de semaine en tant que classe. En stylisant différemment .Saturday et .Sunday, vous pouvez facilement repérer les week-ends dans la liste.

Étendre les modèles enfants

Il est maintenant temps de connecter les modèles enfants au modèle parent base.html. Mettez à jour entries/templates/entries/entry_list.html pour que cela ressemble à ceci :

<!-- entries/templates/entries/entry_list.html -->

{% extends "entries/base.html" %}

{% block content %}
    {% for entry in entry_list %}
        <article>
            <h2 class="{{ entry.date_created|date:'l' }}">
                {{ entry.date_created|date:'Y-m-d H:i' }}
            </h2>
            <h3>
                <a href="{% url 'entry-detail' entry.id %}">
                    {{ entry.title }}
                </a>
            </h3>
        </article>
    {% endfor %}
{% endblock %}

La balise de modèle {% block %} définit une partie du document qu'un modèle enfant peut remplacer. Pour activer cela, vous devez déclarer que votre modèle enfant étend le modèle parent et définir un élément de bloc portant le même nom. Avec la balise de modèle {% extends %} à la ligne 3, vous définissez entries/base.html comme parent. {% block %} et {% endblock %} aux lignes 5 et 18 encapsulent le balisage qui sera placé dans le bloc content du parent.

Faites de même pour entries/templates/entries/entries_detail.html :

<!-- entries/templates/entries/entries_detail.html -->

{% extends "entries/base.html" %}

{% block content %}
    <article>
        <h2>{{ entry.date_created|date:'Y-m-d H:i' }}</h2>
        <h3>{{ entry.title }}</h3>
        <p>{{ entry.content }}</p>
    </article>
{% endblock %}

Les deux modèles héritent de la structure HTML et du style de leur modèle parent. Ils partagent le même titre et le même titre <h1>, ainsi que le style fourni par diary.css. Pour voir cela en action, démarrez votre serveur de développement Django et accédez à http://localhost:8000 :

Vous pouvez désormais lire vos entrées avec style. Cependant, lorsque vous souhaitez créer, mettre à jour ou supprimer une entrée, vous devez vous rendre sur le site d'administration de Django. C’est beaucoup trop de clics lorsque vous souhaitez noter rapidement quelques réflexions. Dans l'étape suivante, vous améliorerez votre flux de travail en ajoutant cette fonctionnalité au front-end.

Étape 5 : Gérer vos entrées de journal sur le front-end

Lorsque vous créez et utilisez des applications Web, vous effectuez en permanence quatre opérations de base. Ces opérations sont si courantes qu'elles sont souvent simplement désignées par l'acronyme CRUD :

  • Créer
  • Lire
  • Mettreà jour
  • Supprimer supprimer

Dans le site d'administration de Django, vous pouvez déjà effectuer toutes ces actions. Dans le front-end, vous ne pouvez lire que vos entrées jusqu'à présent. Pour ressembler aux fonctionnalités du site d'administration de Django, vous répéterez ce que vous avez déjà fait pour EntryDetail et EntryList, en ajoutant une vue, un modèle et une URL. .

Ajouter les vues

Dans entries/views.py, vous avez importé ListView et DetailView jusqu'à présent. Mettez à jour vos instructions d'importation pour qu'elles ressemblent à ceci :

# entries/views.py

from django.urls import reverse_lazy
from django.views.generic import (
    ListView,
    DetailView,
    CreateView,
    UpdateView,
    DeleteView,
)

Ajoutez vos trois sous-classes au bas de entries/views.py :

# entries/views.py

class EntryCreateView(CreateView):
    model = Entry
    fields = ["title", "content"]
    success_url = reverse_lazy("entry-list")

class EntryUpdateView(UpdateView):
    model = Entry
    fields = ["title", "content"]

    def get_success_url(self):
        return reverse_lazy(
            "entry-detail",
            kwargs={"pk": self.entry.id}
        )

class EntryDeleteView(DeleteView):
    model = Entry
    success_url = reverse_lazy("entry-list")

Cette fois, il ne suffit pas de connecter les classes à votre modèle Entry. Pour EntryCreateView et EntryUpdateView, vous devez également définir quels champs de modèle doivent être affichés dans le formulaire, comme vous pouvez le voir aux lignes 5 et 10. Votre EntryDeleteView à la ligne 18 effectue uniquement l'action de supprimer un élément d'entrée, vous n'avez donc pas besoin d'y définir de champs.

De plus, vous devez définir où l'utilisateur doit être redirigé après avoir soumis le formulaire de vue. Par défaut, .get_success_url() renvoie simplement la valeur de success_url. Dans EntryUpdateView, vous devez écraser cette méthode.

En fournissant le entry.id comme argument de mot-clé à la ligne 15, vous restez sur la page de détail de l'entrée après l'avoir modifiée. Au lieu d'utiliser des URL, vous utilisez reverse_lazy pour y faire référence par leur nom, comme vous l'avez fait dans vos modèles.

Créer les modèles

Comme auparavant, Django recherche des modèles avec un nom spécifique :

  • Pour EntryDeleteView, il s'agit de entry_confirm_delete.html.
  • Pour EntryCreateView, il s'agit de entry_form.html.
  • Pour EntryUpdateView, ce serait entry_update_form.html.

Lorsque Django ne trouve pas entry_update_form.html, il essaie entry_form.html comme solution de secours. Vous pouvez en profiter en créant un modèle qui gère les deux vues dans entries/templates/entries/ et en ajoutant un formulaire de soumission de base :

<!-- entries/templates/entries/entry_form.html -->

{% extends "entries/base.html" %}
{% block content %}
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <input type="submit" value="Save">
    </form>
    {% if entry %}
        <a href="{% url 'entry-detail' entry.id %}">
            <button>Cancel</button>
        </a>
    {% else %}
        <a href="{% url 'entry-list' %}">
            <button>Cancel</button>
        </a>
    {% endif %}
{% endblock %}

Lorsque ce modèle est chargé par CreateView, le formulaire sera vide et son annulation vous ramènera à la liste des entrées. Lorsqu'il est chargé par CreateUpdateView, il sera prérempli avec le titre et le contenu actuels de l'entrée. L'annulation vous amènera à la page de détails de l'entrée.

Il existe plusieurs façons d'afficher un formulaire dans un modèle. Avec {{ form.as_p }} à la ligne 7, Django affichera les champs que vous avez définis dans la vue enveloppés dans des paragraphes. Chaque fois que vous publiez du contenu dans des formulaires Django, vous devez également y inclure la balise de modèle {% csrf_token %} à la ligne 6. Il s'agit d'une mesure de sécurité destinée à empêcher la falsification de requêtes intersites.

Comme pour les autres modèles, vous ajoutez {% extends "entries/base.html" %} à la ligne 3 pour étendre le modèle de base. Ensuite, vous définissez ce qu'il faut inclure dans la balise block content entre les lignes 4 et 18. Vous utilisez le même modèle pour entry_confirm_delete.html dans entries/templates/entries/  :

<!-- entries/templates/entries/entry_confirm_delete.html -->

{% extends "entries/base.html" %}
{% block content %}
    <form method="post">{% csrf_token %}
        <p>
            Are you sure you want to delete
            <em>"{{ entry.title }}"</em>
            created on {{ entry.date_created|date:'Y-m-d' }}?
        </p>
        <input type="submit" value="Confirm">
    </form>
    <a href="{% url 'entry-detail' entry.id %}">
        <button>Cancel</button>
    </a>
{% endblock %}

Ce modèle apparaîtra lorsque vous êtes sur le point de supprimer une entrée. Mentionner "{{ Entry.title }}" et {{ Entry.created_date|date:'Y-m-d' }> dans le formulaire vous rappelle quelle entrée vous supprimeriez en appuyant sur Confirmer.

Créer les URL

Après avoir créé les vues et leurs modèles, créez leurs itinéraires pour y accéder dans le front-end. Ajoutez trois chemins supplémentaires vers urlpatterns dans entries/urls.py :

# entries/urls.py

urlpatterns = [
    path(
        "",
        views.EntryListView.as_view(),
        name="entry-list"
    ),
    path(
        "entry/<int:pk>",
        views.EntryDetailView.as_view(),
        name="entry-detail"
    ),
    path(
        "create",
        views.EntryCreateView.as_view(),
        name="entry-create"
    ),
    path(
        "entry/<int:pk>/update",
        views.EntryUpdateView.as_view(),
        name="entry-update",
    ),
    path(
        "entry/<int:pk>/delete",
        views.EntryDeleteView.as_view(),
        name="entry-delete",
    ),
]

Pour entry-create, vous n'avez besoin que d'un chemin create de base. Comme le entry-detail créé précédemment, entry-update et entry-delete ont besoin d'une clé primaire pour identifier quelle entrée doit être mise à jour ou supprimée.

Vous pouvez désormais créer, mettre à jour et supprimer des entrées pour votre agenda directement dans le front-end. Démarrez le serveur Web de développement et visitez http://localhost:8000/create pour le tester. Si vous souhaitez comparer votre code avec celui de ce tutoriel, cliquez sur le lien ci-dessous :

Vous pouvez retrouver les fichiers liés à cette étape dans le répertoire source_code_step_5/.

Étape 6 : Améliorer votre expérience utilisateur

En utilisant votre journal, vous êtes peut-être tombé sur quelques bizarreries qui rendent la navigation un peu ennuyeuse. Dans cette étape, vous les aborderez un par un. Vous verrez que de petits changements dans l’interface peuvent avoir un impact important sur l’expérience utilisateur de votre agenda.

Gérez votre réussite

C’est toujours agréable d’avoir des retours, surtout quand ils sont positifs. À l'aide du cadre de messages, vous pouvez définir rapidement des messages flash ponctuels qui s'affichent une fois que vous avez soumis vos formulaires. Pour utiliser cette fonctionnalité, importez les messages et SuccessMessageMixin dans entries/views.py :

# entries/views.py

from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin

EntryListView et EntryDetailView sont des vues en lecture et ne gèrent pas de formulaire. Ils peuvent afficher un message dans le modèle, mais ils n’en envoient pas. Cela signifie que vous n'avez pas besoin de sous-classer SuccessMessageMixin pour eux. EntryCreateView, EntryUpdateView et EntryDeleteView, en revanche, ajoutent une notification au stockage des messages, vous devez donc ajuster leur fonctionnalité :

# entries/views.py

class EntryCreateView(SuccessMessageMixin, CreateView):
    model = Entry
    fields = ["title", "content"]
    success_url = reverse_lazy("entry-list")
    success_message = "Your new entry was created!"

class EntryUpdateView(SuccessMessageMixin, UpdateView):
    model = Entry
    fields = ["title", "content"]
    success_message = "Your entry was updated!"

    def get_success_url(self):
        return reverse_lazy(
            "entry-detail",
            kwargs={"pk": self.object.pk}
        )

Après avoir hérité de SuccessMessageMixin dans EntryCreateView à la ligne 3 et dans EntryUpdateView à la ligne 9, vous définissez un success_message pour eux sur lignes 7 et 12. Surtout lorsque vous effectuez une action destructrice comme supprimer une entrée, il est crucial de signaler que tout s'est bien passé. Pour afficher un message dans un DeleteView, vous devez ajouter une méthode .delete() personnalisée et ajouter manuellement votre success_message personnalisé au cadre de messages. :

# entries/views.py

class EntryDeleteView(DeleteView):
    model = Entry
    success_url = reverse_lazy("entry-list")
    success_message = "Your entry was deleted!"

    def delete(self, request, *args, **kwargs):
        messages.success(self.request, self.success_message)
        return super().delete(request, *args, **kwargs)

Vous avez besoin de cette méthode supplémentaire à la ligne 8 car la classe DeleteView n'est pas un ancêtre d'un FormView. C'est pourquoi vous pouvez ignorer l'ajout du SuccessMessageMixin dans votre EntryDeleteView à la ligne 3.

Cliquez sur le lien ci-dessous pour voir le contenu complet de entries/views.py. Vous pouvez le trouver dans le répertoire source_code_step_6/ :

Maintenant que les vues envoient des messages, vous devez améliorer les modèles pour les afficher.

Recevoir le message

Les messages sont stockés dans le stockage des messages. En le parcourant, vous affichez tous les messages qui se trouvent actuellement dans le stockage des messages. Dans les modèles Django, vous accomplissez cela en utilisant la balise de modèle de messages. De la façon dont vous avez construit le journal et structuré les modèles, il vous suffit de l'ajouter à entries/base.html :

<!-- entries/base.html -->

<h1><a href="/">Dear diary …</a></h1>

{% if messages %}
    <ul class="messages">
    {% for message in messages %}
        <li class="message">
            {{ message }}
        </li>
    {% endfor %}
    </ul>
{% endif %}

{% block content %}{% endblock %}

En enveloppant la liste des messages dans {% if messages %} aux lignes 4 et 12, vous vous assurez qu'elle ne sera affichée que sous condition, s'il y a des messages dans le stockage.

Améliorez votre navigation

Pour créer, modifier ou supprimer une entrée, vous devez mémoriser les URL correspondantes, puis les saisir dans la barre d'adresse. Comme c'est fastidieux ! Heureusement, vous pouvez résoudre ce problème en ajoutant des liens vers les vues. Commencez par un lien vers la vue entry-create dans le modèle entries/templates/entries/entry_list.html :

<!-- entries/templates/entries/entry_list.html -->

{% block content %}
<article>
    <h2 class="mark">{% now "Y-m-d H:i" %}</em></h2>
    <a href="{% url 'entry-create' %}"><button>Add new entry</button></a>
</article>

{% for entry in entry_list %}

Ce balisage ressemblera aux autres éléments de la liste des entrées du journal. Ajoutez un nouveau paragraphe au modèle entries/templates/entries/entry_detail.html juste après pour modifier ou supprimer rapidement une entrée :

<!-- entries/templates/entries/entry_detail.html -->

</article>
<p>
    <a href="{% url 'entry-update' entry.id %}">✍️ Edit</a>
    <a href="{% url 'entry-delete' entry.id %}">⛔ Delete</a>
</p>
{% endblock %}

Ce code ajoute deux liens sous les détails de l'entrée qui renvoient respectivement à entry-update et entry-delete.

Stylisez vos messages

Enfin, stylisez les messages flash en ajoutant .messages et .message à la fin de entries/static/css/diary.css :

/* entries/static/css/diary.css */

/* Messages */

.messages {
    padding: 0;
    list-style: none;
}

.message {
    width: 100%;
    background: lightblue;
    padding: 1rem;
    text-align: center;
    margin: 1rem 0;
}

Arrêtez le serveur Web de développement en appuyant sur Ctrl<span>+C dans le terminal et redémarrez il. Visitez ensuite http://localhost:8000 pour voir vos modifications en action. Si les messages ne semblent pas stylisés, vous devrez peut-être vider le cache de votre navigateur pour qu'il recharge les modifications de la feuille de style :

Vous possédez désormais une application Web de journal entièrement utilisable, entièrement construite dans Django. Bien que votre agenda ne soit stocké que localement, c'est une bonne idée de vous assurer que vous seul pouvez y accéder. Ajoutons cette restriction avant de commencer la journalisation.

Étape 7 : Verrouiller votre journal Django

Ce qu'un petit cadenas doré est pour un agenda physique, un formulaire de connexion l'est pour votre agenda numérique. La clé de ce verrou est la combinaison nom et mot de passe que vous utilisez déjà pour vous connecter au site d'administration de Django.

Réutilisez votre connexion administrateur Django

Le système d'authentification fourni par Django est assez basique. Pour d'autres projets avec des utilisateurs réguliers, vous pouvez envisager de le personnaliser. Mais pour votre agenda Django, il suffit de réutiliser le login du site d'administration de Django. Vous verrez que cela fonctionne très bien dans un instant. Tout d’abord, prenons soin de nous déconnecter.

Ajouter un lien de déconnexion

Vous vous déconnectez en visitant une URL spéciale. Django fournit déjà une URL avec le nom admin:logout pour vous déconnecter du site d'administration de Django. Lorsque vous êtes connecté et que vous visitez cette URL depuis n'importe où dans votre projet, Django vous déconnecte automatiquement. Pour accéder rapidement à cette URL, ajoutez-y un lien au bas de entries/templates/entries/base.html :

<!-- entries/templates/entries/base.html -->

{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>My Diary</title>
    <link rel="stylesheet" href="{% static 'css/diary.css' %}">
</head>

<body>
<h1><a href="/">Dear diary …</a></h1>

{% if messages %}
    <ul class="messages">
    {% for message in messages %}
        <li class="message">
            {{ message }}
        </li>
    {% endfor %}
    </ul>
{% endif %}

{% block content %}{% endblock %}

<hr>
<a href="{% url 'admin:logout' %}">Logout</a>
</body>

</html>

Démarrez votre serveur Web de développement, accédez à votre page d'accueil à l'adresse http://localhost:8000 et cliquez sur le lien Déconnexion. Désormais, lorsque vous visitez http://localhost:8000/admin, vous voyez le formulaire de connexion. Cela signifie que vous êtes déconnecté. Lorsque vous visitez à nouveau http://localhost:8000, les entrées de votre journal sont toujours accessibles. Il est temps de changer ça !

Restreindre l'accès à vos vues

Dans Django, vous pouvez définir qui est autorisé à voir quelles vues. Par défaut, ils sont ouverts à tous ceux qui visitent votre site Web. Pour vous assurer que les vues nécessitent l'accès d'un utilisateur authentifié, importez LoginRequiredMixin en haut de entries/views.py :

# entries/views.py

from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse_lazy
from django.views.generic import (
    ListView,
    DetailView,
    CreateView,
    UpdateView,
    DeleteView,
)

from .models import Entry

Une fois qu'une classe de vue utilise LoginRequiredMixin, elle nécessite d'abord une connexion réussie. De plus, vous devez définir une login_url pour que Django sache où vous rediriger lorsque vous n'êtes pas connecté. Au lieu de faire cela pour toutes les classes individuellement, vous pouvez créer une classe de base qui hérite de LoginRequiredMixin et définit le login_url dans entries/views.py :

# entries/views.py

class LockedView(LoginRequiredMixin):
    login_url = "admin:login"

Vous pouvez désormais hériter de LockedView dans toutes vos autres vues qui ne devraient être accessibles qu'aux utilisateurs authentifiés. Modifiez entries/views.py pour que vos classes ressemblent à ceci :

# entries/views.py

class EntryListView(LockedView, ListView):
    model = Entry
    queryset = Entry.objects.all().order_by("-created_date")

class EntryDetailView(LockedView, DetailView):
    model = Entry

class EntryCreateView(LockedView, SuccessMessageMixin, CreateView):
    model = Entry
    fields = ["title", "content"]
    success_url = reverse_lazy("entry-list")
    success_message = "Your new entry was created!"

class EntryUpdateView(LockedView, SuccessMessageMixin, UpdateView):
    model = Entry
    fields = ["title", "content"]
    success_message = "Your entry was updated!"

    def get_success_url(self):
        return reverse_lazy("entry-detail", kwargs={"pk": self.object.pk})

class EntryDeleteView(LockedView, SuccessMessageMixin, DeleteView):
    model = Entry
    success_url = reverse_lazy("entry-list")
    success_message = "Your entry was deleted!"

    def delete(self, request, *args, **kwargs):
        messages.success(self.request, self.success_message)
        return super().delete(request, *args, **kwargs)

Désormais, lorsque vous visitez http://localhost:8000, vous serez redirigé vers le formulaire de connexion Django. Une fois connecté, vous serez redirigé vers la liste des entrées et verrez tout ce qui n’est que pour vos yeux :

Et c'est tout! Vous avez réussi à créer votre propre journal personnel dans Django. Si vous souhaitez comparer votre code avec le code final du projet, alors cliquez sur le lien ci-dessous :

Le code complet du projet se trouve dans le répertoire source_code_step_final/.

Prochaines étapes

Le journal que vous avez créé est entièrement fonctionnel et prêt à l’emploi. Mais c’est aussi une excellente base sur laquelle s’appuyer. Peut-être avez-vous déjà des idées sur la manière d’améliorer encore davantage votre agenda. Ou vous pouvez essayer l’une des idées ci-dessous :

  • Ajoutez une page pour vos entrées les plus récentes.
  • Donnez une couleur à chaque jour de la semaine.
  • Afficher la date de création dans la balise HTML <title>.
  • Créez une sélection d'emoji du jour pour une entrée.
  • Paginez la liste des entrées.

Tout au long de ce didacticiel, vous avez découvert certains concepts et modèles de base fournis par Django. Espérons que cela ait suscité un certain intérêt pour approfondir ce framework Web Python. Si vous souhaitez continuer votre voyage et en savoir plus, vous pouvez consulter ces tutoriels :

  • Vos premiers pas avec Django : configurer un projet Django
  • Commencez avec Django Partie 1 : Créez une application de portefeuille
  • Ce que vous devez savoir pour gérer les utilisateurs dans Django Admin
  • Personnaliser l'administrateur Django avec Python
  • Créez un blog avec Django, Vue et GraphQL

Vous pouvez appliquer les connaissances que vous avez acquises en complétant votre projet de journal à d'autres didacticiels Django et faire passer vos compétences en applications Web au niveau supérieur !

Conclusion

Dans ce didacticiel, vous avez créé un journal personnel à partir de zéro en utilisant Django. Vous avez appris à créer une application Web complète que vous pouvez utiliser au quotidien. Il tire parti des nombreux atouts de Django, notamment le site d'administration, les vues basées sur les classes, le cadre de messages et le système de modèles.

Ce projet Django est également une base parfaite pour vos futurs projets Django. Les étapes que vous avez terminées dans ce projet de journal sont fondamentalement les mêmes pour d'autres projets, comme un blog ou une application de tâches.

Dans ce didacticiel, vous avez appris à :

  • Mettre en place un projet Django
  • Travailler avec la base de données SQLite standard
  • Utilisez le site d'administration de Django
  • Créer des modèles et des vues basées sur les classes
  • Modèles d'imbrication et de style
  • Sécurisez votre agenda avec authentification

Vous pouvez télécharger le code source complet du journal Django en cliquant sur le lien ci-dessous :

Articles connexes