Le framework pour les plans de site (sitemap)
Django est fourni avec un puissant framework pour générer des plans de site permettant de créer facilement des fichiers XML Sitemap.
Présentation générale
Un plan de site est un fichier XML sur votre site web qui indique aux indexeurs des moteurs de recherche à quelle fréquence vos pages sont modifiées et l'importance de certaines pages par rapport à d'autres. Cette information permet aux moteurs de recherche d'indexer votre site.
Le framework sitemap de Django automatise la création de ce fichier XML en vous permettant d'exprimer cette information en Python.
Cela fonctionne d'une manière assez similaire au framework de syndication de Django. Pour créer un plan de site, écrivez simplement une classe Sitemap et faites-y référence dans votre fichier URLconf.
Installation
Instructions pour installer l'application sitemap:
- Ajoutez le paramètre 'django.contrib.sitemaps' à INSTALLED_APPS.
- Vérifiez que le paramètre 'django.template.loaders.app_directories.load_template_source' est bien présent dans TEMPLATE_LOADERS. Il y est par défaut, vous ne devez donc y toucher que si vous l'avez déjà modifié.
- Assurez-vous d'avoir installé le framework sites.
(Note: L'application sitemap n'installe aucune table dans la base de données. La raison pour laquelle celle-ci doit être insérée dans INSTALLED_APPS est qu'il faut s'assurer que le chargeur de template (gabarit) puisse trouver les templates par défaut.)
Initialisation
Pour activer la génération de plan de site sur votre site Django, ajoutez cette ligne à votre fichier URLconf:
(r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps})
Ceci indique à Django qu'il doit construire un plan de site lorsqu'un client accède à /sitemap.xml.
Le nom du fichier plan de site n'est pas important, mais sa position dans l'arborescence l'est. Les moteurs de recherche n'indexeront les liens de votre plan de site qu'à partir d'URL où il se trouve et en-dessous. Par exemple, si sitemap.xml appartient à votre répertoire racine, il peut référencer n'importe quelle URL de votre site. Par contre, si votre plan de site appartient à /content/sitemap.xml, il ne pourra référencer que les URL commençant par /content/.
La vue sitemap nécessite un argument supplémentaire: {'sitemaps': sitemaps}. `` sitemaps`` doit être un dictionnaire qui établit la correspondance entre la description courte d'une section (par exemple, blog ou bien news) et sa classe Sitemap (par exemple, BlogSitemap ou NewsSitemap). Il peut aussi mettre en relation la description avec une instance de la classe Sitemap (e.g., BlogSitemap(une_var)).
La classe Sitemap
Une classe Sitemap est simplement une classe Python représentant une "section" d'entrées dans votre plan de site. Par exemple, une classe Sitemap peut représenter toutes les entrées de votre blog, tandis qu'une autre peut représenter tous les événements de votre agenda.
Dans le cas le plus simple, toutes ces sections sont regroupées dans un fichier sitemap.xml, mais il est également possible d'utiliser le framework pour générer un index de plan de site qui référence des fichiers de plan de site individuels, un par section. (Voir Création d'un index de plan de site plus bas.)
Les classes Sitemap doivent dériver de django.contrib.sitemaps.Sitemap. Elle peuvent apparaître n'importe où dans votre code.
Exemple simple
Considérons que vous avez un système de blog, avec un modèle Entry, et que vous vouliez que votre plan de site comprenne tous les liens vers les entrées de votre blog. Voila à quoi pourrait ressembler votre classe sitemap:
from django.contrib.sitemaps import Sitemap
from mysite.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
Note:
- changefreq et priority sont des attributs de classe correspondant, respectivement, aux éléments <changefreq> et <priority>. On peut les rendre invocables en tant que fonctions, comme lastmod dans l'exemple.
- items() est simplement une méthode pour obtenir en retour une liste d'objets. Les objets de cette liste seront transférés aux méthodes invocables qui correspondraient à une propriété (location, lastmod, changefreq, and priority).
- Avec lastmod on obtient en retour un objet Python de type datetime.
- Dans cet exemple, il n'y a pas de méthode location, mais vous pouvez la mettre afin de spécifier l'URL de votre objet. Par défaut, location() appelle get_absolute_url() sur chaque objet et donne en retour le résultat.
Référence de la classe Sitemap
Une classe Sitemap peut définir les méthodes/attributs suivants:
items
Obligatoire. Méthode qui permet de donner en retour une liste d'objets. Le framework ne se préoccupe pas du type des objets, l'important étant que ces objets puissent être utilisés comme argument pour les méthodes location(), lastmod(), changefreq() et priority().
location
Optionnel. Méthode ou bien attribut.
S'il s'agit d'une méthode, elle doit donner en retour l'URL absolue pour un objet donné renvoyé par items().
S'il s'agit d'un attribut, sa valeur doit être une chaîne de caractères représentant une URL absolue à utiliser pour chaque objet renvoyé par items().
Dans les deux cas, "URL absolue" signifie une URL ne contenant pas le protocole ou le domaine. Exemples:
- bon: '/foo/bar/'
- mauvais: 'example.com/foo/bar/'
- mauvais: 'http://example.com/foo/bar/'
Si location n'est pas présent, le framework appelera la méthode get_absolute_url() sur chaque objet renvoyé par items().
lastmod
Optionnel. Méthode ou bien attribut.
S'il s'agit d'une méthode, elle doit accepter un argument -- un objet renvoyé par items() -- et indiquer en retour la date de la dernière modification de cet objet, sous la forme d'un objet Python datetime.datetime.
S'il s'agit d'un attribut, sa valeur doit être un objet Python datetime.datetime représentant la dernière date de modification pour chaque objet renvoyé par items().
changefreq
Optionnel. Méthode ou bien attribut.
S'il s'agit d'une méthode, elle doit accepter un argument -- un objet renvoyé par items() -- et indiquer en retour la fréquence de modification de cet objet, sous la forme d'une chaîne de caractères.
S'il s'agit d'un attribut, sa valeur doit être une chaîne de caractères représentant la fréquence de modification pour chaque objet renvoyé par items().
Les valeurs possibles pour changefreq, que ce soit une méthode ou un attribut, sont:
- 'always' : en permanence
- 'hourly' : toutes les heures
- 'daily' : quotidiennement
- 'weekly' : chaque semaine
- 'monthly' : mensuellement
- 'yearly' : annuellement
- 'never' : jamais
priority
Optionnel. Méthode ou bien attribut.
S'il s'agit d'une méthode, elle doit accepter un argument -- un objet renvoyé par items() -- et indiquer en retour la priorité de l'objet, sous la forme soit d'un flottant soit d'une chaîne de caractères.
S'il s'agit d'un attribut, sa valeur doit être soit une chaîne de caractères soit un flottant représentant la priorité pour chaque objet renvoyé par items().
Exemple de valeurs pour priority: 0.4, 1.0. Par défaut, la priorité d'une page est 0.5. Voir la documentation sitemaps.org pour plus d'informations.
Raccourcis
Le framework sitemap fournit, dans un but pratique, quelques classes pour les cas d'utilisations courants:
FlatPageSitemap
La classe django.contrib.sitemaps.FlatPageSitemap prend en compte toutes les pages à plat définies dans le SITE_ID en question (voir la documentation sur les sites) et génère une entrée dans le plan de site. Ces entrées contiennent uniquement l'attribut location et non lastmod, changefreq ou priority.
GenericSitemap
La classe GenericSitemap fonctionne avec n'importe quelle vue générique déjà présente. Pour l'utiliser, créez une instance, en passant en paramètre le même info_dict utilisé pour la vue générique. La seule contrainte est d'avoir une entrée queryset dans le dictionnaire. Ce dernier peut aussi contenir une entrée date_field afin de spécifier un champ de date pour les objets récupérés dans le queryset. Ce champ sera alors utilisé pour l'attribut lastmod dans le plan de site généré. On peut aussi passer les arguments mot-clé priority et changefreq au constructeur de GenericSitemap pour spécifier ces attributs dans toutes les URL.
Exemple
Voici un exemple d'un fichier URLConf utilisant les deux raccourcis:
from django.conf.urls.defaults import *
from django.contrib.sitemaps import FlatPageSitemap, GenericSitemap
from mysite.blog.models import Entry
info_dict = {
'queryset': Entry.objects.all(),
'date_field': 'pub_date',
}
sitemaps = {
'flatpages': FlatPageSitemap,
'blog': GenericSitemap(info_dict, priority=0.6),
}
urlpatterns = patterns('',
# some generic view using info_dict
# ...
# the sitemap
(r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps})
)
Création d'un index de plan de site
Le framework sitemap permet aussi de créer un index de plan de site qui référence des fichiers de plan de site individuels, un pour chaque section définie dans votre dictionnaire sitemaps. Les seules différences dans la pratique sont:
- Vous utilisez deux vues dans votre URLconf : django.contrib.sitemaps.views.index et django.contrib.sitemaps.views.sitemap.
- La vue django.contrib.sitemaps.views.sitemap doit accepter un argument mot-clé section.
Voici à quoi devraient ressembler les lignes correspondantes de URLconf pour l'exemple ci-dessus:
(r'^sitemap.xml$', 'django.contrib.sitemaps.views.index', {'sitemaps': sitemaps})
(r'^sitemap-(?P<section>.+).xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps})
Cela générera automatiquement un fichier sitemap.xml qui référencera à la fois sitemap-flatpages.xml et sitemap-blog.xml. La classe Sitemap et le dictionnaire sitemaps ne sont pas modifiés.
Faire un "ping" sur Google
Vous aurez peut-être envie de faire un "ping" sur Google lors d'une modification de votre plan de site, afin qu'il réindexe votre site. Le framework fournit une fonction pour cela: django.contrib.sitemaps.ping_google().
ping_google() accepte un argument optionnel, sitemap_url, qui doit être l'URL absolue de votre plan de site (par exemple, '/sitemap.xml'). Si cet argument n'est pas fourni, ping_google() essaiera de retrouver votre plan de site en effectuant une recherche inversée à partir de votre URLconf.
ping_google() lève l'exception django.contrib.sitemaps.SitemapNotFound s'il ne peut pas déterminer l'URL de votre plan de site.
Une manière pratique 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):
super(Entry, self).save()
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 tout autre gestionnaire de tâche. Cette fonction envoie une requête HTTP vers les serveurs de Google, donc peut-être faudra-t-il éviter d'ajouter cette surcharge au réseau à chaque fois que vous appelez save().