Faits saillants de Django : la création de modèles permet d'économiser des lignes (partie 2)

Publié: 2022-03-10
Résumé rapide ↬ La création de code frontal dans Django avec des modèles et un rendu côté serveur combine le contrôle précis du HTML manuscrit avec le code propre et les fonctionnalités puissantes des pages générées. Nous explorons la décomposition d'une page Web complexe en plusieurs modèles, la composition de ces composants et l'application de balises et de filtres pour refactoriser une page HTML simple.

Certaines approches simples de création de sites Web nécessitent qu'un développeur écrive chaque ligne de code HTML à la main. À l'autre extrême, les constructeurs de sites commerciaux sans code créent automatiquement tout le code HTML pour l'utilisateur, souvent au détriment de la lisibilité du code résultant. La modélisation se situe au milieu de ce spectre, mais plus proche du HTML manuscrit que, par exemple, de la génération d'une structure de page dans une application d'une seule page utilisant React ou une bibliothèque similaire. Ce point idéal sur le continuum offre de nombreux avantages du HTML manuel à partir de zéro (code sémantique/lisible, contrôle total sur la structure de la page, chargements de page rapides) et ajoute une séparation des préoccupations et de la concision, tout cela au détriment du temps passé à écrire. HTML modifié à la main. Cet article montre comment utiliser les modèles Django pour écrire des pages complexes.

Spectre HTML. ( Grand aperçu )

Le sujet d'aujourd'hui s'applique au-delà du framework Django. Flask (un autre framework Web) et Pelican (un générateur de site statique) ne sont que deux des nombreux autres projets Python qui utilisent la même approche de création de modèles. Jinja2 est le moteur de template utilisé par les trois frameworks, bien que vous puissiez en utiliser un autre en modifiant les paramètres du projet (à proprement parler, Jinja2 est un sur-ensemble de template Django). Il s'agit d'une bibliothèque autonome que vous pouvez intégrer à vos propres projets même sans cadre, de sorte que les techniques de cet article sont largement utiles.

Pièces précédentes de la série :

  • Faits saillants de Django : modèles d'utilisateurs et authentification (partie 1)
  • Faits saillants de Django : modèles, administration et exploitation de la base de données relationnelle (partie 3)
  • Faits saillants de Django : se disputer les ressources statiques et les fichiers multimédias (partie 4)
Plus après saut! Continuez à lire ci-dessous ↓

Rendu côté serveur

Un modèle est juste un fichier HTML où le HTML a été étendu avec des symboles supplémentaires. Rappelez-vous ce que HTML signifie : H yper T ext M arkup L anguage. Jinja2, notre langage de modèles, ajoute simplement au langage des symboles de balisage significatifs supplémentaires. Ces structures supplémentaires sont interprétées lorsque le serveur restitue le modèle pour servir une page HTML simple à l'utilisateur (c'est-à-dire que les symboles supplémentaires du langage de modèle n'apparaissent pas dans la sortie finale).

Le rendu côté serveur est le processus de construction d'une page Web en réponse à une requête. Django utilise le rendu côté serveur pour servir les pages HTML au client. A la fin de son exécution, une fonction de visualisation combine la requête HTTP, un ou plusieurs modèles, et éventuellement des données accédées lors de l'exécution de la fonction pour construire une seule page HTML qu'elle envoie en réponse au client. Les données vont de la base de données, à travers la vue, et dans le modèle pour se rendre à l'utilisateur. Ne vous inquiétez pas si cette explication abstraite n'a pas tout à fait de sens, nous nous tournerons vers un exemple concret pour le reste de cet article.

Mise en place

Pour notre exemple, nous prendrons une page Web assez complexe, le modèle d'administration de Start Bootstrap, et réécrirons le code HTML en tant que modèle Jinja2. Notez que la bibliothèque sous licence MIT utilise un système de modèles différent (basé sur JavaScript et Pug) pour générer la page que vous voyez, mais leur approche diffère considérablement des modèles de style Jinja2, donc cet exemple est plus une rétro-ingénierie qu'une traduction de leur excellent projet open-source. Pour voir la page Web que nous allons construire, vous pouvez consulter l'aperçu en direct de Start Bootstrap.

J'ai préparé un exemple d'application pour cet article. Pour que le projet Django s'exécute sur votre propre ordinateur, démarrez votre environnement virtuel Python 3, puis exécutez les commandes suivantes :

 pip install django git clone https://github.com/philipkiely/sm_dh_2_dashboard.git cd sm_dh_2_dashboard python manage.py migrate python manage.py createsuperuser python manage.py loaddata employee_fixture.json python manage.py runserver

Ensuite, ouvrez votre navigateur Web et accédez à https://127.0.0.1:8000 . Vous devriez voir la même page que l'aperçu, correspondant à l'image ci-dessous.

Page principale du tableau de bord. ( Grand aperçu )

Étant donné que ce didacticiel est axé sur le frontend, l'application Django sous-jacente est très simple. Cela peut sembler beaucoup de configuration pour présenter une seule page Web, et pour être juste, c'est le cas. Cependant, cette configuration pourrait également prendre en charge une application beaucoup plus robuste.

Maintenant, nous sommes prêts à parcourir le processus de transformation de ce fichier HTML de 668 lignes en un site Django correctement architecturé.

Modèles et héritage

La première étape de la refactorisation de centaines de lignes de code HTML en code propre consiste à diviser les éléments en leurs propres modèles, que Django composera en une seule page Web lors de l'étape de rendu.

Jetez un oeil dans les pages/modèles . Vous devriez voir cinq fichiers :

  • base.html , le modèle de base que chaque page Web étendra. Il contient le <head> avec le titre, les importations CSS, etc.
  • navbar.html , le code HTML de la barre de navigation supérieure, un composant à inclure si nécessaire.
  • footer.html , le code du pied de page, un autre composant à inclure si nécessaire.
  • sidebar.html , le HTMl pour la barre latérale, un troisième composant à inclure si nécessaire.
  • index.html , le code unique de la page principale. Ce modèle étend le modèle de base et inclut les trois composants.

Django assemble ces cinq fichiers comme Voltron pour rendre la page d'index. Les mots clés qui permettent cela sont {% block %} , {% include %} et {% extend %} . Dans base.html :

 {% block content %} {% endblock %}

Ces deux lignes laissent de la place aux autres modèles qui étendent base.html pour insérer leur propre code HTML. Notez que content est un nom de variable, vous pouvez avoir plusieurs blocs avec des noms différents dans un modèle, ce qui donne de la flexibilité aux modèles enfants. Nous voyons comment étendre cela dans index.html :

 {% extends "base.html" %} {% block content %} <!-- HTML Goes Here --> {% endblock %}

L'utilisation du mot clé extends avec le nom du modèle de base donne à la page d'index sa structure, nous évitant de copier dans l'en-tête (notez que le nom du fichier est un chemin relatif sous forme de chaîne entre guillemets). La page d'index comprend les trois composants communs à la plupart des pages du site. Nous apportons ces composants avec include balises d'inclusion comme ci-dessous :

 {% extends "base.html" %} {% block content %} {% include "navbar.html" %} {% include "sidebar.html" %} <!--Index-Specific HTML--> {% include "footer.html" %} <!--More Index-Specific HTML--> {% endblock %}

Dans l'ensemble, cette structure offre trois avantages clés par rapport à l'écriture de pages individuellement :

  • Code SEC (Ne vous répétez pas)
    En factorisant le code commun dans des fichiers spécifiques, nous pouvons modifier le code à un seul endroit et refléter ces modifications sur toutes les pages.
  • Lisibilité accrue
    Plutôt que de faire défiler un fichier géant, vous pouvez isoler le composant spécifique qui vous intéresse.
  • Séparation des préoccupations
    Le code pour, par exemple, la barre latérale doit maintenant être au même endroit, il ne peut y avoir de balises de script malveillantes flottant au bas du code ou d'autres mélanges entre ce qui devrait être des composants séparés. La factorisation des pièces individuelles oblige à cette bonne pratique de codage.

Bien que nous puissions économiser encore plus de lignes de code en plaçant les composants spécifiques dans le modèle base.html , les garder séparés offre deux avantages. La première est que nous sommes capables de les intégrer exactement là où ils appartiennent dans un seul bloc (cela ne concerne que le footer.html qui va à l'intérieur de la div principale du bloc de content ). L'autre avantage est que si nous devions créer une page, disons une page d'erreur 404, et que nous ne voulions pas de la barre latérale ou du pied de page, nous pourrions les laisser de côté.

Ces capacités sont comparables au cours de création de modèles. Maintenant, nous nous tournons vers des balises puissantes que nous pouvons utiliser dans notre index.html pour fournir des fonctionnalités dynamiques et enregistrer des centaines de lignes de code.

Deux balises fondamentales

C'est très loin d'être une liste exhaustive des balises disponibles. La documentation de Django sur les modèles fournit une telle énumération. Pour l'instant, nous nous concentrons sur les cas d'utilisation de deux des éléments les plus courants du langage de template. Dans mon propre travail, je n'utilise essentiellement que les balises for et if de manière régulière, bien que la douzaine ou plus d'autres balises fournies aient leurs propres cas d'utilisation, que je vous encourage à consulter dans la référence du modèle.

Avant d'en venir aux balises, je veux faire une note sur la syntaxe. La balise {% foo %} signifie que "foo" est une fonction ou une autre capacité du système de template lui-même, tandis que la balise {{ bar }} signifie que "bar" est une variable transmise au modèle spécifique.

Pour les boucles

Dans le fichier index.html restant, la plus grande section de code de plusieurs centaines de lignes est le tableau. Au lieu de cette table codée en dur, nous pouvons générer la table dynamiquement à partir de la base de données. Rappelez python manage.py loaddata employee_fixture.json à partir de l'étape de configuration. Cette commande utilisait un fichier JSON, appelé Django Fixture, pour charger les 57 enregistrements d'employés dans la base de données de l'application. Nous utilisons la vue dans views.py pour transmettre ces données au modèle :

 from django.shortcuts import render from .models import Employee def index(request): return render(request, "index.html", {"employees": Employee.objects.all()})

Le troisième argument positionnel à render est un dictionnaire de données mis à la disposition du modèle. Nous utilisons ces données et la balise for pour construire le tableau. Même dans le modèle original à partir duquel j'ai adapté cette page Web, le tableau des employés était codé en dur. Notre nouvelle approche supprime des centaines de lignes de tableaux répétitifs codés en dur. index.html contient désormais :

 {% for employee in employees %} <trv <td>{{ employee.name }}</td> <td>{{ employee.position }}</td> <td>{{ employee.office }}</td> <td>{{ employee.age }}</td> vtd>{{ employee.start_date }}</td> <td>${{ employee.salary }}</td> </tr> {% endfor %}

Le plus gros avantage est que cela simplifie grandement le processus de mise à jour de la table. Plutôt que de demander à un développeur de modifier manuellement le code HTML pour refléter une augmentation de salaire ou une nouvelle embauche, puis de pousser ce changement en production, tout administrateur peut utiliser le panneau d'administration pour effectuer des mises à jour en temps réel (https://127.0.0.1/admin, utilisez les informations d'identification que vous avez créées avec python manage.py createsuperuser pour y accéder). C'est un avantage d'utiliser Django avec ce moteur de rendu au lieu de l'utiliser seul dans un générateur de site statique ou une autre approche de template.

Sinon

La balise if est une balise incroyablement puissante qui vous permet d'évaluer les expressions dans le modèle et d'ajuster le code HTML en conséquence. Des lignes comme {% if 1 == 2 %} sont parfaitement valides, bien qu'un peu inutiles, car elles donnent le même résultat à chaque fois. Là où la balise if brille, c'est lors de l'interaction avec les données transmises au modèle par la vue. Considérez l'exemple suivant de sidebar.html :

 <div class="sb-sidenav-footer"> <div class="small"> Logged in as: </div> {% if user.is_authenticated %} {{ user.username }} {% else %} Start Bootstrap {% endif %} </div>

Notez que l'objet utilisateur entier est passé dans le modèle par défaut, sans que nous ne spécifions quoi que ce soit dans la vue pour que cela se produise. Cela nous permet d'accéder au statut d'authentification de l'utilisateur (ou à son absence), au nom d'utilisateur et à d'autres fonctionnalités, y compris le suivi des relations de clé étrangère pour accéder aux données stockées dans un profil utilisateur ou un autre modèle connecté, le tout à partir du fichier HTML.

Vous craignez peut-être que ce niveau d'accès ne présente des risques pour la sécurité. Cependant, n'oubliez pas que ces modèles sont destinés à une infrastructure de rendu côté serveur. Après avoir construit la page, les balises se sont consommées et sont remplacées par du HTML pur. Ainsi, si une instruction if introduit des données dans une page sous certaines conditions, mais que les données ne sont pas utilisées dans une instance donnée, ces données ne seront pas du tout envoyées au client, car l'instruction if est évaluée côté serveur. Cela signifie qu'un modèle correctement construit est une méthode très sécurisée pour ajouter des données sensibles aux pages sans que ces données ne quittent le serveur, sauf si nécessaire. Cela dit, l'utilisation de modèles Django ne supprime pas la nécessité de communiquer des informations sensibles de manière sécurisée et cryptée, cela signifie simplement que des contrôles de sécurité comme user.is_authenticated peuvent se produire en toute sécurité dans le code HTML car il est traité côté serveur.

Cette fonctionnalité a un certain nombre d'autres cas d'utilisation. Par exemple, dans la page d'accueil d'un produit général, vous pouvez masquer les boutons « S'inscrire » et « Se connecter » et les remplacer par un bouton « Se déconnecter » pour les utilisateurs connectés. Une autre utilisation courante consiste à afficher et à masquer les messages de réussite ou d'erreur pour des opérations telles que la soumission de formulaires. Notez que vous ne masquez généralement pas la page entière si l'utilisateur n'est pas connecté. Une meilleure façon de modifier la page Web entière en fonction du statut d'authentification de l'utilisateur consiste à la gérer dans la fonction appropriée dans views.py .

Filtration

Une partie du travail de la vue consiste à formater les données de manière appropriée pour la page. Pour ce faire, nous avons une puissante extension aux balises : les filtres. Il existe de nombreux filtres disponibles dans Django pour effectuer des actions telles que la justification du texte, le formatage des dates et l'ajout de nombres. Fondamentalement, vous pouvez considérer un filtre comme une fonction appliquée à la variable dans une balise. Par exemple, nous voulons que nos numéros de salaire se lisent "1 200 000 $" au lieu de "1200000". Nous allons utiliser un filtre pour faire le travail dans index.html :

 <td>${{ employee.salary|intcomma }}</td>

Le caractère pipe | est le filtre qui applique la commande intcomma à la variable employee.salary . Le caractère "$" ne vient pas du template, pour un élément comme celui qui apparaît à chaque fois, il est plus simple de le coller juste en dehors de la balise.

Notez que intcomma nous oblige à inclure {% load humanize %} en haut de notre index.html et 'django.contrib.humanize', dans notre INSTALLED_APPS dans settings.py . Ceci est fait pour vous dans l'exemple d'application fourni.

Conclusion

Le rendu côté serveur avec le moteur Jinja2 fournit des outils clés pour créer un code frontal propre, adaptable et réactif. La séparation des pages en fichiers permet des composants DRY avec une composition flexible. Les balises fournissent des fonctionnalités fondamentales pour afficher les données transmises depuis la base de données par les fonctions d'affichage. Bien faite, cette approche peut augmenter la vitesse, les capacités de référencement, la sécurité et la convivialité du site, et constitue un aspect essentiel de la programmation dans Django et des frameworks similaires.

Si vous ne l'avez pas déjà fait, consultez l'exemple d'application et essayez d'ajouter vos propres balises et filtres à l'aide de la liste complète.

Django Highlights est une série présentant des concepts importants du développement Web dans Django. Chaque article est écrit comme un guide autonome sur une facette du développement de Django destiné à aider les développeurs et les concepteurs front-end à mieux comprendre «l'autre moitié» de la base de code. Ces articles sont principalement construits pour vous aider à comprendre la théorie et les conventions, mais contiennent des exemples de code, qui sont écrits en Django 3.0.

Pièces précédentes de la série :

  • Faits saillants de Django : modèles d'utilisateurs et authentification (partie 1)
  • Faits saillants de Django : modèles, administration et exploitation de la base de données relationnelle (partie 3)
  • Faits saillants de Django : se disputer les ressources statiques et les fichiers multimédias (partie 4)