• 20 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 12/12/19

Ajoutez les gabarits manquants

Log in or subscribe for free to enjoy all this course has to offer!

Dans le chapitre précédent vous avez appris à ajouter un gabarit ! Maintenant, intéressons-nous de plus près aux balises de gabarits.

Commençons par l'ajout d'un lien sur l'image d'un album qui mène vers sa fiche détaillée.

Générer les urls dynamiquement

La balise url

Pour rappel, la vue detail est liée au schéma d'URL suivant : r'^(?P<album_id>[0-9]+)/$'. Par exemple : store/2. Vous pourriez bien sûr générer l'url ainsi :

list.html

<a href="/store/{{ album.id }}">
<img class="img-responsive" src="{{ album.picture }}" alt="{{ album.title }}">
</a>

Mais vous êtes alors dépendant de votre schéma d'URL ! Que se passe-t-il si vous devez le changer, par exemple pour renommer "store" en "shop" ? ? Vous mettrez à jour le fichier d'URLs, sans penser à modifier les gabarits. Et alors tous les liens seront cassés ! 😵

Evidemment, vous voulez vous éviter cette catastrophe ! C'est pourquoi Django intègre une balise dans les gabarits qui génère cette URL automatiquement : url. Elle prend en paramètres le nom de la vue.

Chaque vue a un nom ? Est-il créé automatiquement par Django ?

Encore une fois, la magie n'existe pas ! Vous devez le spécifier vous-même dans le fichier d'URLs. Pour cela, ajoutez le paramètre name.

store/urls.py

...
urlpatterns = [
url(r'^$', views.listing, name='listing'),
url(r'^(?P<album_id>[0-9]+)/$', views.detail, name='detail'),
url(r'^search/$', views.search, name='search'),
]

Vérifiez que cela fonctionne en modifiant les listes :

list.html

<a href="{% url 'detail' %}">
<img class="img-responsive" src="{{ album.picture }}" alt="{{ album.title }}">
</a>

Cela fonctionne... presque ! Il manque une information importante : l'identifiant de l'album ! Ajoutez-le en paramètre de la balise url :

list.html

<a href="{% url 'detail' album_id=album.id %}">
<img class="img-responsive" src="{{ album.picture }}" alt="{{ album.title }}">
</a>

Parfait !

Les espaces de nom

Notre projet ne comprend qu'une seule application. Mais beaucoup de projets en Django sont organisés autour de bien plus ! Imaginez un instant que deux applications aient deux URLs au nom identique. Comment Django les différenciera-t-il ?

Réponse : il ne le peut pas si vous ne lui indiquez pas comment le faire !

C'est à cela que servent les espaces de nom (namespaces en anglais). Ils regroupent les URLs autour d'un nom qui les identifie.

Cette fois-ci, ouvrez le fichier d'URLs qui se trouve au niveau du projet et non de l'application :

disquaire_project/urls.py

urlpatterns = [
url(r'^$', views.index),
url(r'^store/', include('store.urls', namespace='store')),
url(r'^admin/', admin.site.urls)
]

A présent, vous pouvez utiliser cet espace de noms dans les gabarits : ajoutez-le avant le nom d'une vue en le séparant avec deux points. Par exemple : {% url 'store:listing' %}

list.html

...
<a href="{% url 'store:detail' album_id=album.id %}">
<img class="img-responsive" src="{{ album.picture }}" alt="{{ album.title }}">
</a>

Avant de continuer, mettez à jour la barre de navigation en ajoutant les URLs adéquates.

base.html

...
<ul class="nav navbar-nav">
<li>
<a href="{% url 'store:listing' %}">Tous nos disques</a>
</li>
</ul>

Bien ! Tout est en place ! Ajoutons les gabarits manquants pour les vues detailsearch et listing.

Ajout des gabarits manquants

Reprenez les maquettes et décelez les éléments dont vous aurez besoin dans chaque gabarit :

  • Page de détail : titre de l'album, nom des artistes, identifiant de l'album, formulaire et image de l'album.

  • Page "tous nos disques" : les albums disponibles.

  • Page affichant les résultats d'une recherche : la requête de la recherche et la liste des albums correspondant.

Mettez à jour les vues en ajoutant les variables nécessaires :

views.py

# ...
def index(request):
albums = Album.objects.filter(available=True).order_by('-created_at')[:12]
context = {
'albums': albums
}
def listing(request):
albums = Album.objects.filter(available=True)
context = {
'albums': albums
}
def detail(request, album_id):
album = Album.objects.get(pk=album_id)
artists = [artist.name for artist in album.artists.all()]
artists_name = " ".join(artists)
context = {
'album_title': album.title,
'artists_name': artists_name,
'album_id': album.id,
'thumbnail': album.picture
}
def search(request):
# ...
title = "Résultats pour la requête %s"%query
context = {
'albums': albums,
'title': title
}

Puis indiquez à chaque vue le gabarit à utiliser.

Simplification du rendu des gabarits

Charger un gabarit, ajouter des variables et renvoyer une réponse HTTP sont des étapes si communes que Django fournit un raccourci : la méthode render(). Voici comment l'utiliser :

from django.shortcuts import render
def index(request):
context = {'title': 'Mon super titre'}
return render(request, 'store/index.html', context)

Plus besoin d'utiliser loader et HttpResponse ! Remplacez-les par l'import de render.

Créez les gabarits (qui sont vides pour le moment) et chargez-les dans les vues :

views.py

from django.shortcuts import render
from .models import Album, Artist, Contact, Booking
def index(request):
# ...
return render(request, 'store/index.html', context)
def listing(request):
# ...
return render(request, 'store/listing.html', context)
def detail(request, album_id):
# ...
return render(request, 'store/detail.html', context)
def search(request):
# ...
return render(request, 'store/search.html', context)

Ajoutez le contenu de ces gabarits. Faites l'exercice par vous-même puis regardez ma proposition pour la page de détail.

Quant à la page "tous nos disques", voici ce que je vous propose :

listing.html

{% extends 'store/base.html' %}
{% block content %}
{% include 'store/list.html' with list_title='Tous nos disques' %}
{% endblock %}

list.html

<div class="col-lg-12">
<hr>
<h2 class="intro-text text-center">{{ list_title }}
</h2>
<hr class="detail-separator">
</div>

Pourquoi ajouter with?

Cela permet de passer un paramètre supplémentaire à un gabarit. Comme vous pouvez le constater c'est très pratique !

Mettez également à jour index.html pour afficher un titre :

index.html

{% include 'store/list.html' with list_title='Nos derniers disques' %}

Passons désormais à la page des résultats de recherche !

Les filtres

La page des résultats de recherche affiche également le nom de la requête en titre de la page. Vous pouvez de nouveau utiliser with !

search.html

{% extends 'store/base.html' %}
{% block content %}
{% include 'store/list.html' with list_title=title %}
{% endblock %}

Un des albums de ma base de données a été enregistré par Them. Je teste si tout fonctionne en tapant l'URL suivante : http://127.0.0.1:8000/store/search/?query=them.

Et là, c'est le drame !

Avez-vous trouvé l'erreur ?

J'avais laissé la structure conditionnelle suivante :

if not albums.exists():
message = "Misère de misère, nous n'avons trouvé aucun résultat !"
else:
albums = ["<li>{}</li>".format(album.title) for album in albums]
message = """
Nous avons trouvé les albums correspondant à votre requête ! Les voici :
<ul>{}</ul>
""".format("</li><li>".join(albums))

Supprimez-la, tout simplement ! Cette vérification serait bien plus pertinente dans le gabarit à présent !

D'ailleurs, mettez à jour list.html en utilisant une balise if.

list.html

...
{% if albums|length_is:"0" %}
<div class="text-center">
Palsambleu ! Nous n'avons trouvé aucun résultat à cette requête. Même pas de quoi se ronger la chique !
Partez de nouveau à l'abordage !
</div>
{% else %}
{% for album in albums %}
...
{% endfor %}
{% endif %}

La structure conditionnelle est un peu étrange, vous ne trouvez pas ? En Python pur, vous auriez plutôt écrit le code suivant :

if len(albums) == 0:
return "Palsambleu !"
else:
return albums

Or, ici, nul besoin d'ajouter deux points à la fin ni de compter le nombre d'occurrences ! Nous avons utilisé une baliseif, et un filtrelength_is.

Il en existe plusieurs ! Prenez le temps de tous les découvrir en lisant la documentation officielle.

Bravo, toutes les vues sont prêtes ! Presque... Il manque une page d'erreur ! Découvrez comment l'ajouter dans le chapitre suivant.

Code de ce chapitre

Retrouvez l'intégralité du code sur ce dépôt GitHub.

Example of certificate of achievement
Example of certificate of achievement