Le système des plans de site (sitemap
)¶
Django est livré avec un système de génération de plans de site à haut niveau qui permet de créer facilement des fichiers XML sitemap.
Aperçu¶
Un plan de site « sitemap » est un fichier XML sur un site Web indiquant aux robots des moteurs de recherche à quelle fréquence les pages changent et comment certaines pages « importantes » sont en relation avec d’autres pages du site. Cette information aide les moteurs de recherche à indexer un site.
L’application sitemap de Django automatise la création de ce fichier XML en permettant d’exprimer cette information sous forme de code Python.
Cela fonctionne un peu comme le système de syndication de Django. Pour créer un plan de site, il suffit d’écrire une classe Sitemap
et de la référencer dans la configuration d’URL.
Installation¶
Pour installer l’application sitemap, procédez comme suit :
- Ajoutez
'django.contrib.sitemaps'
au réglageINSTALLED_APPS
. - Vérifiez la présence d’un moteur
DjangoTemplates``dont l'option ``APP_DIRS
vautTrue
dans le réglageTEMPLATES
. Il y est par défaut, de sorte que vous aurez uniquement besoin de l’ajouter si vous avez modifié ce réglage. - Assurez-vous d’avoir installé le
gestionnaire de sites
.
(Remarque : l’application sitemap n’installe aucune table de base de données. La seule raison pour laquelle elle doit être présente dans INSTALLED_APPS
est que la fonction de chargement des gabarits Loader()
doit pouvoir trouver les gabarits par défaut.)
Initialisation¶
-
views.
sitemap
(request, sitemaps, section=None, template_name='sitemap.xml', content_type='application/xml')¶
Pour activer la génération du plan du site d’un site Django, ajoutez cette ligne à la configuration d’URL:
from django.contrib.sitemaps.views import sitemap
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps},
name='django.contrib.sitemaps.views.sitemap')
Cela indique à Django de construire un plan de site lorsqu’un client accède à /sitemap.xml
.
Le nom du fichier sitemap n’est pas important, mais l’emplacement l’est. Les moteurs de recherche n’indexeront que les liens du plan de site à partir du niveau actuel de l’URL et en-dessous. Par exemple, si sitemap.xml
réside dans le répertoire racine, il peut faire référence à n’importe quelle URL du site. Cependant, si le fichier sitemap réside dans /content/sitemap.xml
, il ne peut référencer que des URL qui commencent par /content/
.
La vue sitemap
accepte un paramètre supplémentaire obligatoire : {'sitemaps': sitemaps}
. sitemaps
doit être un dictionnaire qui associe une étiquette de section courte (par exemple, blog
ou nouvelles
) à sa classe Sitemap
(par exemple, BlogSitemap
ou NewsSitemap
). Il peut également s’appliquer à une instance de classe Sitemap
(par exemple, BlogSitemap(ma_variable)
).
Classes Sitemap
¶
Une classe Sitemap
est une simple classe Python qui représente une « section » d’entrées dans votre plan de site. Par exemple, une classe Sitemap
pourrait représenter toutes les entrées de votre blog, tandis qu’une autre pourrait représenter tous les évènements d’un calendrier d’évènements.
Dans le cas le plus simple, toutes ces sections sont regroupées dans un seul sitemap.xml
, mais il est également possible d’utiliser le système pour générer un index de sitemap qui référence d’autres fichiers sitemap individuels, un par section (voir Création d’un index de plan de site ci-dessous).
Les classes Sitemap
doivent être des sous-classes de django.contrib.sitemaps.Sitemap
. Elles peuvent résider n’importe où dans votre code source.
Un exemple simple¶
Supposons que vous avez un système de blog, avec un modèle Entry
. Vous souhaitez que le plan de site contienne les liens vers tous les articles de blog. Voici à quoi la classe de plan de site pourrait ressembler :
from django.contrib.sitemaps import Sitemap
from blog.models import Entry
class BlogSitemap(Sitemap):
changefreq = "never"
priority = 0.5
def items(self):
return Entry.objects.filter(is_draft=False)
def lastmod(self, obj):
return obj.pub_date
Remarque :
changefreq
etpriority
sont des attributs de classe correspondant respectivement aux éléments<changefreq>
et<priority>
. Il est possible qu’ils correspondent à des fonctions, comme pourlastmod
dans l’exemple ci-dessus.items()
est tout simplement une méthode qui renvoie une liste d’objets. Les objets renvoyés seront transmis à toute méthode exécutable correspondant à une propriété de sitemap (location
,lastmod
,changefreq
etpriority
).lastmod
doit renvoyer un objetdatetime
.- Il n’y a pas de méthode
location
dans cet exemple, mais vous pouvez la fournir afin de préciser l’URL de l’objet. Par défaut,location()
appelleget_absolute_url()
pour chaque objet et renvoie le résultat.
Référence de la classe Sitemap
¶
-
class
Sitemap
[source]¶ Une classe
Sitemap
peut définir les méthodes/attributs suivants :-
items
[source]¶ Obligatoire. Une méthode qui renvoie une liste d’objets. Le système ne se soucie pas de quel type d’objet il s’agit ; tout ce qui compte, c’est que ces objets sont transmis aux méthodes
location()
,lastmod()
,changefreq()
etpriority()
.
-
location
[source]¶ Facultatif. Soit une méthode, soit un attribut.
Si c’est une méthode, elle doit renvoyer le chemin absolu pour le dit objet renvoyé par
items()
.Si c’est un attribut, sa valeur doit être une chaîne représentant un chemin absolu à utiliser pour chaque objet renvoyé par
items()
.Dans les deux cas, « chemin absolu » signifie une URL qui ne comprend ni le protocole ni le domaine. Exemples :
- Bon :
'/foo/bar/'
- Mauvais :
'example.com/foo/bar/'
- Mauvais :
'https://example.com/foo/bar/'
Si
location
n’est pas fourni, le système appelle la méthodeget_absolute_url()
de chaque objet renvoyé paritems()
.Pour indiquer un protocole autre que
'http'
, utilisezprotocol
.- Bon :
-
lastmod
¶ Facultatif. Soit une méthode, soit un attribut.
Si c’est une méthode, elle doit accepter un paramètre, un objet renvoyé par
items()
, et renvoyer la date/heure de dernière modification de cet objet, en tant quedatetime
.Si c’est un attribut, sa valeur doit être un objet
datetime
représentant la date/heure de dernière modification pour chaque objet renvoyé paritems()
.Si tous les éléments d’un plan de site possèdent
lastmod
, le plan de site généré parviews.sitemap()
comportera un en-têteLast-Modified
égal à la valeurlastmod
la plus récente. Vous pouvez activer l’intergicielConditionalGetMiddleware
pour que Django réponde de manière appropriée aux requêtes contenant un en-têteIf-Modified-Since
, ce qui évitera d’envoyer le plan de site si celui-ci n’a pas changé.
-
changefreq
¶ Facultatif. Soit une méthode, soit un attribut.
Si c’est une méthode, elle doit accepter un paramètre, un objet renvoyé par
items()
, et renvoyer la fréquence de modification de cet objet, en tant que chaîne.Si c’est un attribut, sa valeur doit être une chaîne représentant la fréquence de modification de chaque objet renvoyé par
items()
.Les valeurs possibles pour
changefreq
, que ce soit une méthode ou un attribut, sont :'always'
(toujours)'hourly'
(chaque heure)'daily'
(quotidiennement)'weekly'
(chaque semaine)'monthly'
(chaque mois)'yearly'
(annuellement)'never'
(jamais)
-
priority
¶ Facultatif. Soit une méthode, soit un attribut.
Si c’est une méthode, elle doit accepter un paramètre, un objet renvoyé par
items()
, et renvoyer la priorité de cet objet, en tant que chaîne ou nombre à virgule.Si c’est un attribut, sa valeur doit être une chaîne ou un nombre à virgule représentant la priorité de chaque objet renvoyé par
items()
.Exemples de valeurs pour
priority
:0.4
,1.0
. La priorité par défaut d’une page est de0.5
. Voir la documentation de sitemaps.org pour plus d’informations.
-
protocol
¶ Facultatif.
Cet attribut définit le protocole (
'http'
ou'https'
) des URL dans le plan du site. S’il n’est pas défini, le protocole avec lequel le plan du site a été demandé sera utilisé. Si le plan du site est construit en dehors du contexte d’une requête, la valeur par défaut est'http'
.
-
limit
¶ Facultatif.
Cet attribut définit le nombre maximum d’URL incluses sur chaque page du plan de site. Sa valeur ne doit pas dépasser la valeur par défaut de
50000
, qui est la valeur limite supérieure autorisée par le protocole des plans de site.
-
Raccourcis¶
L’infrastructure sitemap fournit une classe pratique pour un cas courant :
-
class
GenericSitemap
[source]¶ La classe
django.contrib.sitemaps.GenericSitemap
permet de créer un plan du site en lui passant un dictionnaire qui doit contenir au minimum une entréequeryset
. Ce jeu de requête sera utilisé pour générer les éléments du plan du site. Le dictionnaire peut aussi contenir une clédate_field
qui définit un champ de date pour les objets récupérés parqueryset
. Ce champ sera utilisé pour l’attributlastmod
dans le plan du site généré. Vous pouvez également passer les paramètres nomméspriority
etchangefreq
au constructeur deGenericSitemap
pour définir ces attributs pour toutes les URL.
Exemple¶
Voici un exemple de configuration d’URL utilisant GenericSitemap
:
from django.conf.urls import url
from django.contrib.sitemaps import GenericSitemap
from django.contrib.sitemaps.views import sitemap
from blog.models import Entry
info_dict = {
'queryset': Entry.objects.all(),
'date_field': 'pub_date',
}
urlpatterns = [
# some generic view using info_dict
# ...
# the sitemap
url(r'^sitemap\.xml$', sitemap,
{'sitemaps': {'blog': GenericSitemap(info_dict, priority=0.6)}},
name='django.contrib.sitemaps.views.sitemap'),
]
Plan de site pour les vues statiques¶
Il peut souvent être nécessaire de faire indexer par les robots des moteurs de recherche des vues qui ne sont ni des pages de détail d’un objet, ni des pages statiques. La solution est de fournir une liste explicite de noms d’URL pour ces vues dans items
et d’appeler reverse()
dans la méthode location
du sitemap. Par exemple :
# sitemaps.py
from django.contrib import sitemaps
from django.urls import reverse
class StaticViewSitemap(sitemaps.Sitemap):
priority = 0.5
changefreq = 'daily'
def items(self):
return ['main', 'about', 'license']
def location(self, item):
return reverse(item)
# urls.py
from django.conf.urls import url
from django.contrib.sitemaps.views import sitemap
from .sitemaps import StaticViewSitemap
from . import views
sitemaps = {
'static': StaticViewSitemap,
}
urlpatterns = [
url(r'^$', views.main, name='main'),
url(r'^about/$', views.about, name='about'),
url(r'^license/$', views.license, name='license'),
# ...
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps},
name='django.contrib.sitemaps.views.sitemap')
]
Création d’un index de plan de site¶
-
views.
index
(request, sitemaps, template_name='sitemap_index.xml', content_type='application/xml', sitemap_url_name='django.contrib.sitemaps.views.sitemap')¶
Le système sitemap a également la possibilité de créer un index de plan de site qui référence des fichiers sitemap individuels, un pour chaque section définie dans le dictionnaire sitemaps
. Les seules différences dans l’utilisation sont les suivantes :
- Vous utilisez deux vues dans la configuration d’URL :
django.contrib.sitemaps.views.index()
etdjango.contrib.sitemaps.views.sitemap()
. - La vue
django.contrib.sitemaps.views.sitemap()
doit accepter un paramètre nommésection
.
Voici à quoi ressembleraient les lignes appropriées de la configuration d’URL pour l’exemple ci-dessus :
from django.contrib.sitemaps import views
urlpatterns = [
url(r'^sitemap\.xml$', views.index, {'sitemaps': sitemaps}),
url(r'^sitemap-(?P<section>.+)\.xml$', views.sitemap, {'sitemaps': sitemaps},
name='django.contrib.sitemaps.views.sitemap'),
]
Cela générera automatiquement un fichier sitemap.xml
faisant référence à la fois à sitemap-flatpages.xml
et à sitemap-blog.xml
. Les classes Sitemap
et le dictionnaire sitemaps
ne changent aucunement.
Vous devriez créer un fichier d’index lorsqu’un plan de site contient plus de 50 000 URL. Dans ce cas, Django pagine automatiquement le plan du site et l’index reflétera cette situation.
Si vous n’utilisez pas la vue sitemap ordinaire – par exemple, si elle est enveloppée par un décorateur de mise en cache – vous devez nommer votre vue sitemap et passer sitemap_url_name
à la vue d’index :
from django.contrib.sitemaps import views as sitemaps_views
from django.views.decorators.cache import cache_page
urlpatterns = [
url(r'^sitemap\.xml$',
cache_page(86400)(sitemaps_views.index),
{'sitemaps': sitemaps, 'sitemap_url_name': 'sitemaps'}),
url(r'^sitemap-(?P<section>.+)\.xml$',
cache_page(86400)(sitemaps_views.sitemap),
{'sitemaps': sitemaps}, name='sitemaps'),
]
Personnalisation de gabarit¶
Si vous souhaitez utiliser un gabarit différent pour chaque plan de site ou d’index de plan de site disponible sur un site, vous pouvez l’indiquer en passant un paramètre template_name
aux vues sitemap
et index
via la configuration d’URL :
from django.contrib.sitemaps import views
urlpatterns = [
url(r'^custom-sitemap\.xml$', views.index, {
'sitemaps': sitemaps,
'template_name': 'custom_sitemap.html'
}),
url(r'^custom-sitemap-(?P<section>.+)\.xml$', views.sitemap, {
'sitemaps': sitemaps,
'template_name': 'custom_sitemap.html'
}, name='django.contrib.sitemaps.views.sitemap'),
]
Ces vues renvoient des instances TemplateResponse
permettant de personnaliser facilement les données de réponse avant le processus de rendu. Pour plus de détails, consultez la documentation de TemplateResponse.
Variables de contexte¶
Lors de la personnalisation des gabarits pour les vues index()
et sitemap()
, vous pouvez compter sur les variables de contexte suivantes.
Accueil¶
La variable sitemaps
est une liste des URL absolues vers chacun des plans du site.
Sitemap¶
La variable urlset
est une liste d’URL devant apparaître dans le plan du site. Chaque URL expose des attributs tels que définis dans la classe Sitemap
:
changefreq
(fréquence de modification)item
(élément)lastmod
(date de dernière modification)location
(adresse)priority
(priorité)
L’attribut item
a été ajouté pour chaque URL afin de permettre une personnalisation plus souple des gabarits, comme pour les Google news sitemaps. En supposant que items()
de Sitemap
renvoie une liste d’éléments avec des champs publication_date
et tags
, le code ci-dessous devrait générer un plan de site compatible avec Google News :
<?xml version="1.0" encoding="UTF-8"?>
<urlset
xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
{% spaceless %}
{% for url in urlset %}
<url>
<loc>{{ url.location }}</loc>
{% if url.lastmod %}<lastmod>{{ url.lastmod|date:"Y-m-d" }}</lastmod>{% endif %}
{% if url.changefreq %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %}
{% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %}
<news:news>
{% if url.item.publication_date %}<news:publication_date>{{ url.item.publication_date|date:"Y-m-d" }}</news:publication_date>{% endif %}
{% if url.item.tags %}<news:keywords>{{ url.item.tags }}</news:keywords>{% endif %}
</news:news>
</url>
{% endfor %}
{% endspaceless %}
</urlset>
Signalement à Google¶
Lorsqu’un plan de site change, il peut être souhaitable de le signaler à Google, afin qu’il sache qu’il doit réindexer le site. Le système sitemaps fournit une fonction pour faire exactement cela : django.contrib.sitemaps.ping_google()
.
-
ping_google
()[source]¶ ping_google()
accepte un paramètre facultatif,sitemap_url
, qui doit être le chemin absolu vers le plan du site (par exemple,'/sitemap.xml'
). Si ce paramètre n’est pas fourni,ping_google()
tente de trouver lui-même le plan du site en effectuant une recherche inverse dans la configuration d’URL.ping_google()
génère l’exceptiondjango.contrib.sitemaps.SitemapNotFound
si elle ne peut pas déterminer l’URL du plan du site.
Inscription préalable chez Google !
La commande ping_google()
ne fonctionne que si vous avez inscrit le site avec Google Webmaster Tools.
Une façon utile d’appeler ping_google()
est de le faire à partir de la méthode save()
d’un modèle :
from django.contrib.sitemaps import ping_google
class Entry(models.Model):
# ...
def save(self, force_insert=False, force_update=False):
super(Entry, self).save(force_insert, force_update)
try:
ping_google()
except Exception:
# Bare 'except' because we could get a variety
# of HTTP-related exceptions.
pass
Toutefois, une solution plus efficace serait d’appeler ping_google()
à partir d’un script cron ou de tout autre tâche planifiée. La fonction effectue une requête HTTP vers les serveurs de Google, il n’est donc pas forcément souhaitable d’introduire cette charge réseau chaque fois que save()
est appelée.