1. Livres & vidéos
  2. Django
  3. Introduction aux vues
Extrait - Django Concevez vos applications web professionnelles en Python : du modèle de données au déploiement
Extraits du livre
Django Concevez vos applications web professionnelles en Python : du modèle de données au déploiement Revenir à la page d'achat du livre

Introduction aux vues

Template view

Pour visualiser le code relatif à ce chapitre : git diff v1.3.4..v1.4.0.

1. Retour sur le modèle MVT

Django est un cadriciel qui utilise le patron d’architecture MVT, pour modèle, vue, gabarit.

Jusqu’à présent, nous avons introduit la partie modèle. Cette partie permet de modéliser les données, de les structurer pour les stocker d’une manière simple et conforme à la réalité.

Cette partie fournit aussi les outils nécessaires pour lire ces données, mais aussi les créer, les modifier ou les supprimer.

La partie vue consiste à créer des outils qui vont utiliser le modèle pour réaliser un affichage, par la création d’une page HTML, ou encore créer, modifier ou supprimer des données en proposant des pages adaptées qui contiendront des formulaires, par exemple.

Créer une vue, c’est écrire une fonction Python ou une classe Python.

Cette dernière va renvoyer des données brutes. Elles peuvent être envoyées telles quelles, converties au format JSON, ce que nous verrons plus tard, ou injectées dans un gabarit HTML qui les utilisera pour générer la page HTML renvoyée à l’utilisateur.

La séparation entre le code HTML géré par les gabarits et le code Python qui va générer toutes les données et faire toutes les actions est très claire.

Un des avantages de cela est que les templates peuvent être donnés à des graphistes qui auront tout le loisir de travailler dessus pour styliser les pages, sans avoir besoin de comprendre le code Python qui se trouve dans les vues.

2. Notion de routage

Une application web est accessible par une URL. Voici un exemple :

https://intranet.exemple.com:9805/chemin/qui/determine/la/vue?param1=42&param2=34

Pour commencer, le vocabulaire associé aux URL :

  • https est le schéma ou scheme en anglais.

  • intranet est le nom de sous-domaine.

  • exemple.com est le nom de domaine.

  • 9805 est le port à utiliser.

  • chemin/qui/determine/la/vue est, sans surprise, le chemin ou path en anglais. 

  • Param1 et param2 sont les deux paramètres de la requête.

Le scheme est une notion importante : il précise le protocole utilisé pour la communication entre...

List view

Pour visualiser le code relatif à ce chapitre : git diff v1.4.0..v1.4.1.

1. Vue dédiée aux listes

De la même manière que Django propose une classe pour gérer les pages de gabarit, il en propose une autre pour gérer les listes d’objets d’un modèle donné.

L’avantage de cette classe est qu’elle permet de créer, en quelques lignes, une vue très complète : elle effectue l’essentiel du travail tout en restant facile à personnaliser.

Voici cette vue :

from django.views.generic import ListView 
from django.utils.translation import gettext_lazy as gettext 
 
from .models import Game 
 
 
class GameListView(ListView): 
    model = Game 
 
    def get_context_data(self, **kwargs): 
        data = super().get_context_data(**kwargs) 
        data['page_title'] = gettext("Game's list") 
        return data  

Les deux premières lignes de la classe réalisent l’essentiel du travail : elles créent une classe héritant de ListView et précisent le modèle dont nous voulons produire la liste des objets.

Nous reconnaissons ensuite la méthode get_context_data, qui permet de préciser le titre de la page attendu par le gabarit master.html.

Au passage, sachez qu’un gabarit qui n’a pas une donnée qu’il attend va considérer que cette donnée est nulle. Vous ne verrez donc pas de message d’erreur si vous oubliez...

Detail view

Pour visualiser le code relatif à ce chapitre : git diff v1.4.0..v1.4.1.

1. Vue dédiée à l’affichage d’un objet

De la même manière que Django propose une classe pour gérer les listes d’objets d’un modèle donné, il en propose une autre pour gérer un objet particulier de ce même modèle.

Comme la classe précédente, celle-ci est très rapide à écrire lorsqu’elle est utilisée de manière classique, tout en restant hautement personnalisable.

Voici cette vue :

from django.views.generic import DetailView 
from django.utils.translation import gettext_lazy as gettext 
 
from .models import Game 
 
 
class GameDetailView(DetailView): 
    model = Game 
 
    def get_context_data(self, **kwargs): 
        data = super().get_context_data(**kwargs) 
        obj = self.get_object() 
        data['page_title'] = str(gettext("Game: {}")).format(obj.name) 
        return data  

Exactement comme dans la section précédente, les deux premières lignes de la classe réalisent l’essentiel...

Update view

Pour visualiser le code relatif à ce chapitre : git diff v1.4.0..v1.4.1.

1. Vue dédiée à la modification d’un objet

La vue permettant de modifier un objet est réalisée en héritant de UpdateView. Elle fait appel à un formulaire. Ce dernier peut être généré automatiquement en précisant dans la classe le nom des champs dans un attribut fields.

from django.views.generic import UpdateView 
from django.utils.translation import gettext_lazy as gettext 
from django.urls import reverse_lazy 
 
from .models import Game 
 
 
class GameUpdateView(UpdateView): 
    model = Game 
    fields = ( 
        "name", 
        "duration", 
        "status", 
        "level", 
    ) 
    success_url = reverse_lazy('game:list') 
 
    def get_context_data(self, **kwargs): 
        data = super().get_context_data(**kwargs) 
        obj = self.get_object() 
        data['page_title'] = str(gettext("Update Game: 
{}")).format(obj.name) 
        return data  

La méthode get_context_data est presque identique à celle de la section précédente.

Nous constatons ici la présence d’un nouvel attribut success_url.

En effet, par défaut, lorsque l’utilisateur valide un formulaire, les données soumises vont être validées.

Cette validation se fait d’abord par rapport à toutes les contraintes posées sur les différents champs du modèle ainsi qu’aux validateurs, comme nous avons pu le tester avec la méthode full_clean. Lorsque nous utilisons un formulaire spécifique, comme nous le ferons plus bas, il est possible d’ajouter des contraintes supplémentaires.

Cette validation peut se terminer de deux manières possibles : soit elle...

Create view

Pour visualiser le code relatif à ce chapitre : git diff v1.4.0..v1.4.1.

1. Vue dédiée à la création d’un objet

La vue pour permettre de créer un objet est réalisée en héritant de CreateView. Elle fait appel à un formulaire. Ce dernier peut être généré automatiquement uniquement en précisant dans la classe le nom des champs dans un attribut fields ou par l’utilisation d’un formulaire, comme vu pour l’UpdateView.

Voici cette vue :

from django.views.generic import CreateView 
from django.utils.translation import gettext_lazy as gettext 
 
from .models import Game 
from .forms import GameForm 
 
 
class GameCreateView(CreateView): 
    model = Game 
    form_class = GameForm 
    success_url = reverse_lazy('game:list') 
 
    def get_context_data(self, **kwargs): 
        data = super().get_context_data(**kwargs) 
        obj = self.get_object() 
        data['page_title'] = str(gettext("Update Player: 
{}")).format(obj.name) 
        return data  

Cette classe ressemble...

Delete view

Pour visualiser le code relatif à ce chapitre : git diff v1.4.0..v1.4.1.

1. Vue dédiée à la suppression d’un objet

La suppression d’un objet se fait en deux temps. Lorsque nous affichons la page, nous envoyons une requête HTTP de type GET, ce qui affiche un formulaire de confirmation.

Lorsque nous validons ce formulaire, une requête POST est envoyée et entraîne la suppression de l’objet. Il n’est pas possible d’envoyer directement cette requête POST sans passer par le formulaire, grâce à la protection CSRF, c’est le formulaire qui va nous donner le jeton dont on a besoin.

La vue permettant de supprimer un objet est réalisée en héritant de DeleteView.

Voici cette vue :

from django.views.generic import DeleteView 
from django.utils.translation import gettext_lazy as gettext 
from django.urls import reverse_lazy 
 
from .models import Game 
 
 
class GameDeleteView(DeleteView): 
    model = Game 
    success_url = reverse_lazy('game:list') 
 
    def get_context_data(self, **kwargs): 
        data = super().get_context_data(**kwargs) 
        obj = self.get_object() 
        data['page_title']...

Authentification

Pour visualiser le code relatif à ce chapitre : git diff v1.4.5..v1.4.6.

1. Solution utilisant les vues de Django

Django dispose déjà d’un module django.contrib.auth qui contient toutes les vues nécessaires pour gérer l’authentification, mais également des vues pour changer le mot de passe ou pour le remettre à zéro.

Il est ainsi possible d’ajouter ces vues dans le fichier project/urls.py :

urlpatterns = [ 
    [path('', HomeView.as_view(), name="home"),] 
    path('accounts/', include('django.contrib.auth.urls')), 
    path('game/', include("app.urls")), 
    path('admin/', admin.site.urls), 
    path("__debug__/", include("debug_toolbar.urls")), 
]  

Nous pouvons vérifier que cela est bien pris en compte avec la commande suivante :

$ make show_urls  

Nous devrions voir, entre autres :

/accounts/login/   django.contrib.auth.views.LoginView  login 
/accounts/logout/  django.contrib.auth.views.LogoutView  logout 
/accounts/password_change/ 
  django.contrib.auth.views.PasswordChangeView  password_change 
/accounts/password_reset/ 
  django.contrib.auth.views.PasswordResetView   password_reset  

Cela est également utile pour récupérer le nom des vues. Ainsi, pour tester ces vues, nous pouvons ajouter, dans le fichier master.html, un bandeau contenant ces liens.

Si l’utilisateur est connecté, nous voulons afficher les liens permettant de se déconnecter et de changer son mot de passe.

Si l’utilisateur n’est pas connecté, autrement dit s’il est en mode anonyme, nous voulons afficher les liens permettant de s’authentifier et de demander la réinitialisation de son mot de passe.

Nous allons donc ajouter ce bloc :

    {% block nav_bar %} 
    {% if user.is_authenticated %} 
        <p>{% translate "Welcome" %} {{ user.first_name }} {{ user.last_name }} ({{...