<< précédentsuivant >>

Chapitre 14: Contributions d’autre sous-framework

Une des nombreuses force de Python est sa philosophie «batteries incluses»: Lorsque vous installé Python, il est livré avec une grande bibliothèque standard de paquets que vous pouvez commencer à utiliser immédiatement, sans avoir à télécharger autre chose. Django s’efforce de suivre cette philosophie, et inclut sa propres bibliothèque standard d’extensions utiles pour les tâches courantes du développement web. Ce chapitre couvre cette collection d’extensions.

La bibliothèque standard de Django

La bibliothèque standard de Django se trouve dans le paquet django.contrib. À l’intérieur de chaque sous-paquets se trouve une extension aux fonctionnalités autonomes. Ces pièces ne sont pas nécessairemant liées, mais quelques sous-paquets de django.contrib peuvent en nécessiter d’autres.

Il n’y à pas de fortes restrictions pour les types de fonctionnalité possibles dans django.contrib. Certains des paquets incluent des modèles (et vous obligent à installer leurs tables dans votre base de données), alors que d’autres consistent seulement en des middlewares ou des balises de gabarit.

L’unique caractéristique que les paquets django.contrib ont en commun est la suivante: si vous deviez retirer entièrement le paquet django.contrib, vous pourrez continuer à utiliser les fonctionnalités fondamentales de Django sans aucuns problèmes. Lorsque les développeurs de Django ajoutent de nouvelles fonctionnalités au framework, ils utilisent cette règle empirique pour décider si cette nouvelle fonctionnalité doit se trouver dans django.contrib ou ailleurs.

django.contrib est constitué de ces paquets:

  • admin: Le site automatique d’administration. Lisez les chapitres 6 et 18.
  • auth: le framework d’identification de Django. Lisez le chapitre 12.
  • comments: une application de commentaires. Cette application est actuellement en fort développement et n’a donc pas pu être entièrement couverte à temps pour la publication de ce livre. Vérifiez le site web Django pour connaitre les dernières informations au sujet de l’application de commentaires.
  • contenttypes: un framework pour s’insérer de les «types» de contenu, où chaque modèle Django installé est un type de contenu séparé. Ce framework est utilisé en interne par d’autres applications «contribs» et est principalement destinée aux développeurs Django très avancés. Ces développeurs peuvent en savoir plus au sujet de cette application en lisant le code source dans django/contrib/contenttypes/.
  • csrf: une protection contre les Cross-Site Request Forgery (CSRF). Lisez la dernière section intitulée «protection CSRF».
  • flatpages: un framework pour gérer le contenu HTML «statiques» dans une base de données. Lisez la dernière section intitulée «Flatpages».
  • humanize: un jeu de filtres de gabarits Django utiles pour ajouter une «touche humaine» aux données. Lisez la section dernière section intitulée «Humaniser les données».
  • markup: un jeu de filtres de gabarits Django qui implémentent de nombreux langages de formatages courants. Lisez la dernière section intitulée «Filtres de formatage».
  • redirects: un framework pour gérer les redirections. Lisez la dernière section intitulé «Redirections».
  • sessions: framework de session de Django. Lisez le chapitre 12.
  • sitemaps: un framework pour générer des fichiers XML cartographiant le site. Lisez le chapitre 11.
  • sites: un framework qui vous laisse utiliser de multiples sites web à partir de la même base de données et de la même installation Django. Lisez la prochaine section, «Sites».
  • syndication: un framework pour générer des flux de syndication RSS et Atom. Lisez le chapitre 11.

Le reste de ce chapitre aborde en détails chaque paquet django.contrib que nous n’avons pas encore couvert dans ce livre.

Sites

Le système de sites de Django est un framework générique qui vous laisse gérer de multiples sites web sur une même base de données et sur un même projet Django. C’est un concept abstrait, il peut être difficile à comprendre, aussi commencerons nous avec une paire de scénarios ou cela s’avère utile.

Scénario 1: Réutiliser les données sur des multiples sites

Comme expliqué au chapitre 1, les sites sous Django que sont LJWorld.com et Lawrence.com sont gérer par le même groupe de presse: le journal Lawrence Journal-World à Lawrence, Kansas. LJWorld.com se concentre sur les informations, alors que Lawrence.com traite surtout les divertissements locaux. Mais parfois, les éditeurs veulent publier un article sur les deux sites.

La manière casse-tête de résoudre le problème serait d’utiliser des bases de données séparées pour chaque site et d’imposer aux rédacteurs de publier la même histoire deux fois: pour le LJWorld.com et à nouveau pour Lawrence.com. Mais ceci est inefficace pour les rédacteurs, et il est redondant de stocker de multiples copies de la même histoire dans la base de données.

La meilleure solution est que les deux sites utilisent la même base de données des articles, et qu’un article soit associé à un ou plusieurs sites via une relation plusieurs-à-plusieurs. Le framework de site sous Django fournit la talbe en base de données dans laquelle les articles peuvent êtres liés. C’est un moyen d’associer les données avec un ou plusieurs «sites».

Scenario 2: Stocker le nom/domaine de votre site en un seul endroit

LJWorld.com et Lawrence.com ont touts deux des fonctionnalités d’alerte mail, qui permettent aux lecteurs inscrit d’être averti dès qu’une nouvelle actualité arrive. C’est assez simple: un lecteur s’inscrit sur un formulaire web, et reçoit immédiatement une courrier lui disant, «Merci pour votre inscription».

Il serait inefficace et redondant d’implémenter le code de ce processus d’inscription deux fois, les sites utilisent donc le même code en coulisses. Mais le message «Merci pour votre inscription» peut être différent pour chaque site. En utilisant les objets Site, nous pouvons faire en sorte que le message de remerciement utilise les valeurs name (par exemple, 'LJWorld.com') et domain (par exemple, 'www.ljworld.com') du site courant.

Le framework de sites sous Django fournit un espace pour vous permettre de stocker le name et le domain pour chaque site dans votre projet Django, ce qui signifie que vous pouvez réutiliser ces valeurs de manière générique.

Comment utiliser le Framework de sites

Le framework de sites est plus une série de conventions qu’un framework. Tout est basé sur deux concepts simples:

  • Le modèle Site, qui se trouve dans django.contrib.sites, possède des champs domain et name.
  • Le paramètre SITE_ID spécifie l’ID de la base de données de l’objet Site associé à ce fichier de paramètres particulier.

La façon dont vous utilisez ces deux concepts est laissé à votre discrétion, mais Django les utilise automatiquement dans certaines occasions via des conventions simples.

Pour installer l’application sites, suivez ces étapes:

  1. Ajoutez 'django.contrib.sites' à votre INSTALLED_APPS.
  2. Lancez la commande manage.py syncdb pour installer la table django_site dans votre base de données.
  3. Ajoutez un ou plusieurs objets Site, soit au travers de l’interface d’administration de Django soit via l’API Python. Créez un objet Site pour chaque site/domaine que ce projet Django motorise.
  4. Definissez le paramètre SITE_ID dans chacun de vos fichiers de paramètres. Cette valeur doit correspondre à l’ID de base de données de l’objet Site pour le site correspondant à ce fichier de paramètres.

Les possibilités du framework Sites

Les sections qui suivent décrivent les diverses choses que vouspouvez faire avec le framework de sites.

Réutiliser les données sur de multiples sites

Pour réutiliser les données sur de multiples sites, comme détaillé lors du premier scénario, créez simplement un ManyToManyField au Site dans votre modèle, par exemple:

from django.db import models
from django.contrib.sites.models import Site

class Article(models.Model):
    headline = models.CharField(maxlength=200)
    # ...
    sites = models.ManyToManyField(Site)

C’est l’infrastructure dont vous avez besoin pour associer les articles à de multiples sites dans votre base de données. Une fois ceci en place, vous pouvez réutiliser le même code des vues Django pour de multiples sites. En continuant avec l’exemple de modèle Article, voici à quoi peut ressembler une vue article_detail:

from django.conf import settings

def article_detail(request, article_id):
    try:
        a = Article.objects.get(id=article_id,
        sites__id=settings.SITE_ID)
    except Article.DoesNotExist:
        raise Http404
    # ...

Cette vue est réutilisable parce qu’elle verifie dynamiquement le site de l’article, selon la valeur du paramètre SITE_ID.

Par exemple, admettons que le fichier de paramètres de LJWorld.com a un SITE_ID placé à 1, et que le fichier de paramètres de Lawrence.com a un SITE_ID valant 2. Si cette vue est appelée lorsque le fichier de paramètres de LJWorld.com est actif, alors il limitera la recherche d’article aux articles pour lesquels la liste des sites inclu LJWorld.com.

Associer du contenu sur un unique site

De la même manière, vous pouvez associer un modèle au modèle du site avec une relation un-à-plusieur en utilisant ForeignKey.

Par exemple, si un article est autorisé sur un unique site, vous pouvez utiliser un modèle ressemeblant à ceci:

from django.db import models
from django.contrib.sites.models import Site

class Article(models.Model):
    headline = models.CharField(maxlength=200)
    # ...
    site = models.ForeignKey(Site)

Ceci à les mêmes avantages que ceux décrits dans la dernière section.

Interférer dans le site courant depuis les vues

À plus bas niveau, vous pouvez utiliser le framework de sites dans vos vues Django pour faire des actions particulières basées sur le site dans lequel la vue est appelée, par exemple:

from django.conf import settings

def my_view(request):
    if settings.SITE_ID == 3:
        # Do something.
    else:
        # Do something else.

Bien sûr, c’est sale de coder en dur l’ID du site comme ceci. Une façon légérement plus propre d’accomplir la même chose consiste a vérifier le domaine du site courant:

from django.conf import settings
from django.contrib.sites.models import Site

def my_view(request):
    current_site = Site.objects.get(id=settings.SITE_ID)
    if current_site.domain == 'foo.com':
        # Do something
    else:
        # Do something else.

L’action de récupérer l’objet Site pour la valeur de settings.SITE_ID étant chose courante, le manager du modèle Site (Site.objects) propose une méthode get_current(). Cet exemple est équivalent au précédent:

from django.contrib.sites.models import Site

def my_view(request):
    current_site = Site.objects.get_current()
    if current_site.domain == 'foo.com':
        # Do something
    else:
        # Do something else.

Note

Dans ce dernier exemple, vous n’avez pas à importer django.conf.settings.

Obtenir le domaine courant pour affichage

Pour une approche DRY (Don’t Repeat Yourself) dans le stockage du nom et du domaine de votre site, comme expliqué dans le «Scenario 2: Stocker le nom/domaine de votre site en un seul endroit», référencez simplement le name et le domain de l’objet Site courant. Par exemple:

from django.contrib.sites.models import Site
from django.core.mail import send_mail

def register_for_newsletter(request):
    # Check form values, etc., and subscribe the user.
    # ...
    current_site = Site.objects.get_current()
    send_mail('Thanks for subscribing to %s alerts' %
    current_site.name,
        'Thanks for your subscription. We appreciate
        it.\n\n-The %s team.' % current_site.name,
        'editor@%s' % current_site.domain,
        [user_email])
    # ...

Pour continuer avec notre exemple de LJWorld.com et Lawrence.com, le courrier provenant de lawrence.com affiche le sujet «Merci de vous êtres inscrit aux alertes de lawrence.com.». Pour LJWorld.com, le courrier à pour sujet «Merci de vous êtres inscrit aux alertes de LJWorld.com». La même fonctionnalité spécifique au site est appliquée au corps du message éléctronique.

Un manière plus flexible (mais aussi plus gourmande en ressource) de faire ceci est d’utiliser le système de gabarit de Django. En considérant que Lawrence.com et LJWorld.com ont des répertoires de gabarits diiférents (TEMPLATE_DIRS), vous pouvez simplement déléguer au système de gabarit, comme ceci:

from django.core.mail import send_mail
from django.template import loader, Context

def register_for_newsletter(request):
    # Check form values, etc., and subscribe the user.
    # ...
    subject =
    loader.get_template('alerts/subject.txt').render(Context({}))
    message =
    loader.get_template('alerts/message.txt').render(Context({}))
    send_mail(subject, message, 'do-not-reply@example.com',
    [user_email])
    # ...

Dans ce cas, vous devez créer les gabarits subject.txt et message.txt à la fois dans les répertoires de gabarits de LJWorld.com et de Lawrence.com. Comme nous l’avons déjà mentionné, ceci vous donne plus de flexibilité, mais aussi plus de complexité.

C’est une bonne idée d’exploiter les objets Site autant que possible pour supprimer la complexité inutile et la redondance.

Obtenir le domaine courant pour les URLS complètes

La convention get_absolute_url() de Django est pratique pour obtenir les URLs de vos objets sans le nom de domaine, mais parfois vous préférerez afficher l’URL complète - avec http://, le domaine et tous le reste - d’un objet. Pour ce faire, vous pouvez utiliser le framework de sites. Voici un exemple simple:

>>> from django.contrib.sites.models import Site
>>> obj = MyModel.objects.get(id=3)
>>> obj.get_absolute_url()
'/mymodel/objects/3/'
>>> Site.objects.get_current().domain
'example.com'
>>> 'http://%s%s' % (Site.objects.get_current().domain,
obj.get_absolute_url())
'http://example.com/mymodel/objects/3/'

CurrentSiteManager

Si Site``s jou un rôle clef dans votre application, considérez l'utilisation du bien pratique ``CurrentSiteManager dans vos modèles. C’est un gestionnaire de modèle (voir l’annexe B) qui filtre automatiquement ses requêtes afin d’y inclure uniquement les objets associés au Site courant.

Utilisez CurrentSiteManager en l’ajoutant à votre modèle explicitement. Par exemple:

from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Photo(models.Model):
    photo = models.FileField(upload_to='/home/photos')
    photographer_name = models.CharField(maxlength=100)
    pub_date = models.DateField()
    site = models.ForeignKey(Site)
    objects = models.Manager()
    on_site = CurrentSiteManager()

Avec ce modèle, Photo.objects.all() retournera tous les objets Photo de la base de données, alors que Photo.on_site.all() retournera uniquement les objets Photo associés au site courant, conformément au paramètre SITE_ID.

En d’autre termes, ces deux instructions sont équivalentes:

Photo.objects.filter(site=settings.SITE_ID)
Photo.on_site.all()

Comment CurrentSiteManager à su que le champ Photo était celui de Site? Il recherche par défaut un champ appelé site. Si votre modèle possède une ForeignKey ou un ManyToManyField appelé autrement que site, vous devrez explicitement préciser cela sous forme de paramètre de CurrentSiteManager. Le modèle suivant, qui propose un champ appelé publish_on, démontre ceci:

from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Photo(models.Model):
    photo = models.FileField(upload_to='/home/photos')
    photographer_name = models.CharField(maxlength=100)
    pub_date = models.DateField()
    publish_on = models.ForeignKey(Site)
    objects = models.Manager()
    on_site = CurrentSiteManager('publish_on')

Si vous essayez d’utiliser CurrentSiteManager en lui passant le nom d’un champ qui n’existe pas, Django lévera une ValueError.

Note

Vous voudrez probablement conserver un Manager normal (qui ne soit pas spécifique au site) dans votre modèle, même si vous utilisez CurrentSiteManager. Comme expliqué dans l’annexe B, si vous définissez un manager manuellement, alors Django ne créera pas le manager automatique objects = models.Manager() pour vous.

De même, certaines parties de Django - nommément, le site d’admin de Django et les vues génériques - utilisent tout gestionnaire défini en premier dans le modèle, aussi lorsque vous voulez que votre site d’administration ait accès à tous les objets (et non pas seulement à ceux qui sont spécifiques au site), placez objects = models.Manager() dans votre modèle, avant de définir CurrentSiteManager.

Comment Django utilise le framework Sites

Bien que l’utilisation du framework de sites ne soit pas requise, elle est fortement encouragée, car ainsi Django en bénéficie en divers endroits. Même si votre installation Django motorise un seul site, vous devriez prendre quelques secondes pour créer l’objet site avec votre domain et votre name, et pointer sur son ID dans votre paramètre SITE_ID.

Voici comment Django utilise le framework de sites:

  • Dans le framework de redirection (consulter la section «Redirtections» plus après), chaque objet redirection est associé à un site particulier. Lorsque Django recherche une redirection, il prend en compte le SITE_ID courant.
  • Dans le framework de commentaires, chaque commentaire est associé à un site particulier. Lorsqu’un commentaire est posté, son site prends la valeur du SITE_ID courant, et lorsque les commentaires sont listés via la balise de gabarit appropriée, seuls les commentaires pour le site courant sont affichés.
  • Dans le framework de pages statiques (voir la section «Pages statique» à suivre), chaque page statique est associée à un site particulier. Lorsqu’une page statique est créée, vous spécifiez son site, et le middleware de page statique vérifie le SITE_ID courant en récupérant les pages statiques à afficher.
  • Dans le framework de syndication (voir les chapitre 11), les gabarits pour title et description ont automatiquement accès à une variable {{ site }}, qui est l’objet Site représentant le site courant. De même, l’accroche pour fournir les éléments d’URLs utilisera le domain de l’objet Site courant si vous ne spécifiez pas un nom de domaine pleinement qualifié.
  • Dans le framwork d’identification (voir le chapitre 12), la vue django.contrib.auth.views.login transmet le nom du Site courant au gabarit {{ site_name }}.

Pages statiques

Vous aurez souvent une application web fonctionnelle basée sur les bases de données, mais vous devrez tout de même ajouter quelques pages statiques, telles que des pages «À propos» ou «Politique de confidentialité». Il est possible d’utliser une serveur web standard tel qu’Apache pour servir ces fichiers sous forme de pages HTML statiques, mais cela introduit un niveau de complexité supplémentaire à votre application, puisqu’alors vous avez à vous soucier de la configuration d’Apache, vous aurez à configurer l’accès en édition à ces fichiers pour les membres de votre équipe, et vous ne pourrez tirer parti du système de gabarit de Django pour le style de vos pages.

La solution à ce problème est l’application «flatpages» de Django, qui réside dans le module django.contrib.flatpages. Cette application vous laisse gérer de telles pages au travers du site d’administration de Django, et vous laisse spécifier les gabarits associés en utilisant le système de gabarits de Django. Elle utilise les modèles Django en coulisses, ce qui signifie qu’elle stocke les pages dans une base de données, tout comme le reste de vos données, et que vous pouvez accéder à ces pages statiques avec l’API de base de données standard sous Django.

Les pages statiques sont déterminées par leur URL et leur site. Lorsque vous créez une page statique, vous spécifiez quelle URL lui est associée, ainsi que le(s) site(s) concerné(s). (Pour en savoir plus au sujet des sites, lisez la section «Sites»).

Using Flatpages

Pour installer l’application «flatpages», suivez ces étapes:

  1. Ajoutez 'django.contrib.flatpages' à votre INSTALLED_APPS. django.contrib.flatpages dépend de django.contrib.sites, assurez vous donc que les deux paquets soient bien parmis les INSTALLED_APPS.
  2. Ajoutez 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware' à votre paramètre MIDDLEWARE_CLASSES.
  3. Lancez la commande manage.py syncdb pour installer les deux tables requises dans votre base de données.

L’application pages statiques crée deux tables dans votre base de données: django_flatpage et django_flatpage_sites. django_flatpage met simplement en correspondance un URL avec un titre maps a URL to a title and bunch of text content. django_flatpage_sites is a many-to-many table that associates a flatpage with one or more sites.

L’application est livrée avec un seul modèle FlatPage, défini dans django/contrib/flatpages/models.py. Il ressemble à ceci:

from django.db import models
from django.contrib.sites.models import Site

class FlatPage(models.Model):
    url = models.CharField(maxlength=100)
    title = models.CharField(maxlength=200)
    content = models.TextField()
    enable_comments = models.BooleanField()
    template_name = models.CharField(maxlength=70, blank=True)
    registration_required = models.BooleanField()
    sites = models.ManyToManyField(Site)

Examinons ces champs un par un:

  • url: l’URL où réside la page statique, purgée du nom de domaine mais incluant la barre oblique initiale (par exemple, /about/contact/).
  • title: le titre de la page statique. Le framework n’en fait rien de spécial. C’est à vous de l’afficher dans votre gabarit.
  • content: le contenu de la page statique (c’est à dire, le HTML de la page). Le framework n’en fait rien de spécial. C’est à vous de l’afficher dans votre gabarit.
  • enable_comments: permet d’activer ou non les commentaires sur cette page statiques. Le framework n’en fait rien de spécial. Vous pouvez utliser cette valeur dans votre gabarit et afficher un formulaire de commentaires si besoin.
  • template_name: le nom du gabarit à utiliser pour le rendu de cette page statique; Ceci est optionel; Si rien n’est précisé ou si ce gabarit n’existe pas, le framework se retournera vers le template flatpages/default.html.
  • registration_required: indique si l’identification est requise pour voir cette page statique. Ceci s’interface avec le framework identification/utilisateur de Django, qui est détaillé plus au chapitre 12.
  • sites: les sites pour lesquels cette page statique est disponible. Ceci s’interface avec le framework de sites Django, qui est détaillé dans la section «Sites» de ce chapitre.

Vous pouvez créer des pages statiques soit au travers de l’interface d’administration de Django soit l’API de base de données de Django. Pour plus d’information sur ce sujet, consultez la section «Ajouter, modifier et supprimer des pages statiques».

Une fois que vous avez créé des pages statiques, FlatpageFallbackMiddleware fait tout le travail. Chaque fois qu’une application Django lève une erreur 404, ce middleware cherche l’URL requis en dernier recours dans la base de données des pages statiques. Plus précisément, il cherche une page statique ayant l’URL données et un ID de site qui correspond au paramètre SITE_ID.

S’il trouve une correspondance, il charge le gabarit de page statique ou le flatpages/default.html si la apge statique ne spécifie pas de gabarit personnalisé. Il passe à ce gabarit une unique variable de contexte, flatpage, qui est l’objet flatpage. Il utilise RequestContext lors du rendu de gabarit.

Si FlatpageFallbackMiddleware ne trouve pas de correspondance, la requête continue d’être traitée, comme d’habitude.

Note

Ce middleware est activé uniquement pour les erreurs 404 (page non trouvée) - pas pour les erreurs 500 (erreur du serveur) ou les autres réponses. Notez aussi que l’ordre des MIDDLEWARE_CLASSES importe. Généralement, vous pouvez placer FlatpageFallbackMiddleware à ou près de la fin de la liste, puisque c’est un dernier recours.

Ajouter, modifier et supprimer des pages statiques

Vouspouvez ajouter, modifier et supprimer des pages statiques de deux façons:

Via l’interface d’administration

Si vous avez activé l’interface automatique d’administration de Django, vous devriez voir une section «Flatpages» sur la page d’index de l’admin. Éditez les pages statiques comme vous éditeriez tout autre objet du système.

Via l’API Python

Comme décrit auparavant, les pages statiques sont représentées par un modèle Django standard se trouvant dans django/contrib/flatpages/models.py. À partir de là, vous pouvez accéder aux objets «page statique» via l’API de base de données de Django, par exemple:

>>> from django.contrib.flatpages.models import FlatPage
>>> from django.contrib.sites.models import Site
>>> fp = FlatPage(
...     url='/about/',
...     title='About',
...     content='<p>About this site...</p>',
...     enable_comments=False,
...     template_name='',
...     registration_required=False,
... )
>>> fp.save()
>>> fp.sites.add(Site.objects.get(id=1))
>>> FlatPage.objects.get(url='/about/')
<FlatPage: /about/ -- About>

Utiliser les gabarits de pages statiques

Par défaut, les pages statiques sont rendues via le gabarit flatpages/default.html, mais vous pouvez outre-passer cela pour une page statique précise avec le champ template_name de l’objet FlatPage.

Créer le gabarit flatpages/default.html reste de votre ressort. Dans votre répertoire de gabarit, créez simplement un répertoire flatpages contenant un fichier default.html.

Les gabarits de pages statiques récupère une variable de contexte unique, flatpage, qui est l’objet flatpage.

Voici un échantillon de gabarit flatpages/default.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
    "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>{{ flatpage.title }}</title>
</head>
<body>
{{ flatpage.content }}
</body>
</html>

Redirections

Le framework de redirection Django vous laisse gérer facilement les redirections en les stockant dans une base de données et en les traitant comme n’importe quel autre objet modèle de Django. Par exemple, vous pouvez utiliser les framework de redirections pour dire à Django, «Redirige toute requête vers /music/ sur ``/sections/arts/music/``». Ceci est pratique lorsque vous avez besoin de déplacer des choses au sein de votre site; Les développeurs web doivent faire tout le nécessaire pour éviter les liens brisés.

System Message: WARNING/2 (<string>, line 682); backlink

Inline literal start-string without end-string.

System Message: WARNING/2 (<string>, line 682); backlink

Inline literal start-string without end-string.

Utiliser le framework de redirection

Pour installer l’application «redirects», suivez ces étapes:

  1. Ajouter 'django.contrib.redirects' à votre INSTALLED_APPS.
  2. Ajouter 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' à votre paramètre MIDDLEWARE_CLASSES.
  3. Lancez la commande manage.py syncdb pour installer l’unique table requise dans votre base de données.

manage.py syncdb crée une table django_redirect dans votre bases de données. C’est une simple table de recherche sur les champs site_id, old_path, et new_path.

Vous pouvez créer des redirections soit au travers de l’interface d’administration soit grâce à l’API de base de données de Django. Pour en savoir plus, lisez la section «Ajouter, modifier et supprimer des redirections».

Lorsque vous avez crée des redirections, la classe RedirectFallbackMiddleware fait tout le travail. Chaque fois qu’une application Django lève une erreur 404, ce middleware cherche l’URL requis en dernier recours dans la base de données des redirections.

Plus précisément, il cherche une redirection ayant le old_path donné et ayant un ID de site qui corresponde au paramètre SITE_ID. (Lisez la section précédente «Sites» pour en savoir plus au sujet de SITE_ID et du framework de sites). Il suit ensuite ces étapes:

  • S’il trouve une correspondance, et que new_path nest pas vide, il redirige vers new_path.
  • S’il trouve une correspondance, et que new_path est vide, il envoi une en-tête 410 («Page déplacée») et une réponse vide (sans contenu).
  • S’il ne trouve pas de correspondance, la requête continue d’être traitée comme d’habitude.

Le middleware ne s’active que pour les erreurs 404 - pas pour les erreurs 500 ou tout autre code de status.

Notez quell’ordre des MIDDLEWARE_CLASSES importe. Usuellement, vous placerez RedirectFallbackMiddleware tout au bout de la liste, puisque c’est une dernier recours.

Note

Si vous utilisez à la fois le middleware de récupération des pages statiques et celui des redirections, considérez celui (redirections ou pages statiques) que vous aimeriez voir contrôlé en premier. Nous vous suggérons les pages statiques avant les redirections (c’est à dire placer le middleware flatpages avant le middleware redirects), mais vous pouvez aussi voir les choses autrement.

Ajouter, modifier et supprimer des redirections

Vous pouvez ajouter, modifier et supprimer les redirections de deux façons:

Via l’interface d’administration

Si vous avez activé l’interface d’administration automatique de Django, vous devriez voir une section «Redirections» sur la page d’index de l’interface d’admin. Éditez les redirections comme vous éditeriez tout autre objet du système.

Via l’API Python

Les redirections sont représentées par un modèle Django standard qui réside dans django/contrib/redirects/models.py. Ceci étant, vous pouvez accéder aux objets redirects via l’API de base de données Django, par exemple:

>>> from django.contrib.redirects.models import Redirect
>>> from django.contrib.sites.models import Site
>>> red = Redirect(
...     site=Site.objects.get(id=1),
...     old_path='/music/',
...     new_path='/sections/arts/music/',
... )
>>> red.save()
>>> Redirect.objects.get(old_path='/music/')
<Redirect: /music/ ---> /sections/arts/music/>

Protection CSRF

Le paquet django.contrib.csrf protège des «Cross-Site Request Forgery» (CSRF).

CSRF, connu aussi sous le nom de «chevauchement de session», est un exploit en matière de sécurité d’un site internet. Il se produit lorsqu’un site web malicieux trompe un utilisateur en l’invitant à son insu à charger l’URL d’un site où l’utilisateur est déjà identifié, pour ensuite tirer parti du status autentifié de celui-ci. Cela peut être un peu sembler un peu étrange de prime abord, aussi allons nous parcourir deux exemples dans cette section.

Un exemple simple de CSRF

Supposons que vous soyez identifié sur un compte de la messagerie web example.com. Ce site de messagerie propose un bouton de déconnexion qui pointe vers l’URL example.com/logout - autrement dit, l’unique action que vous avez besoin de faire pour vous déconnecter est de visiter la page example.com/logout.

Un site malicieu peut vous contraindre à visiter l’URL example.com/logout en incluant cette URL dissimulée dans un <iframe> sur sa propre page (malicieuse). Ainsi, si vous êtes connecté sur le compte de messagerie example.com et que vous visitiez la page malicieuse qui possède un <iframe> vers example.com/logout, le fait de visiter la page malicieuse vous déconnectera d’example.com. Clairement, être déconnecté d’un site de messagerie contre votre volonté n’est pas une terrible faille de sécurité, mais ce même type d’exploit peut arriver à n’importe quel site qui «identifie» les utilisateurs, tel qu’un site de compte bacaire en ligne ou un site de e-commerce.

Un example plus complexe de CSRF

Dans l’exemple précédent, example.com était partiellement en faute parce qu’il autorisait un changement d’état (c’est à dire, déconnecter l’utilisateur) à être appelé depuis la méthode HTTP GET. C’est une bien meilleure pratique que d’utiliser un HTTP POST pour toute requête qui change l’état sur le serveur. Mais même les sites web qui utilisent POST` pour les actions relatives au changement d’état sont vulnérables aux CSRF.

Supposons qu’example.com a amélioré sa fonctionnalité de déconnexion de façon à ce qu’ un bouton <form> soit requis via un POST sur l’URL example.com/logout. Plus précisement, le <form> de déconnexion inclu ce champ caché:

<input type="hidden" name="confirm" value="true" />

Ceci permet qu’un simple POST vers l’URL example.com/logout ne déconnectera pas l’utilisateur; Pour qu’un utilisateur se déconnecte, l’utilisateur doit faire une requête à example.com/logout via POST et envoyer la variable confirm POST avec une valeur à 'true'.

Ensuite, malgré cette sécurité supplémentaire, cet arrangement peut toujours être exploitée par CSRF - la page malicieuse à juste besoin de faire un peu plus de travail. Les attaquants peuvent créer un formulaire entier ciblant votre site, le masquer dans un <iframe> invisible, pour ensuite utiliser Javascript afin de valider ce formulaire automatiquement.

Prévenir les CSRF

Comment, alors, votre propre site peut se protéger de ces exploits ? La première étape est de s’assurer que toutes les requêtes GET sont libre d’effet de bord. De cette façon, si un site malicieux embarque une de vos page sous forme d’<iframe>, il n’y aura pas d’effet négatif.

Cela nous laisse les requêtes POST. La seconde étape consiste à donner à chaque <form> POST un champ caché dont la valeur est secrête et est générée à partir de l’ID de session de l’utilisateur. Ensuite, lors du traitement du formulaire côté serveur, il ne reste plus qu’à contrôler ce champ caché et à lever une erreur s’il n’est pas valide.

C’est exactement ce que fait la couche CSRF préventive, comme détaillé dans les sections qui suivent.

Utilisation du middleware CSRF

La paquet django.contrib.csrf contient seulement un module: middleware.py. Ce module contient une classe Django middleware, CsrfMiddleware, qui implémente la protection CSRF.

Pour activer cette protection CSRF, ajoutez 'django.contrib.csrf.middleware.CsrfMiddleware' au paramètre MIDDLEWARE_CLASSES de votre fichier de paramètres. Ce middleware doit traiter la réponse après SessionMiddleware, CsrfMiddleware doit donc apparaître dans la liste avant SessionMiddleware (puisque la réponse du middleware est effectuée du dernier-au-premier). Ainsi, puisqu’il doit traiter la réponse avant que celle-ci soit compréssée ou autrement dénaturée, CsrfMiddleware doit venir après GZipMiddleware. Une fois que vous avez cela à votre paramètre MIDDLEWARE_CLASSES, vous avez terminé. Lisez la section «Ordre des MIDDLEWARE_CLASSES» au chapitre 13 pour plus d’explication.

Au cas où vous seriez intéressé, voici comment fonctionne CsrfMiddleware. Il fait ces deux choses:

  1. Il modifie les requêtes sortantes en ajoutant un champ de formulaire caché à tous les formulaires POST, avec le nom csrfmiddlewaretoken et une valeur qui est un hachage de l’ID de session enrichi d’une clef secrete. Le middleware ne modifiant pas la réponse s’il n’y a pas d’ID de session fixé, la pénalité en matière de performance est donc négligeable pour les requêtes n’utilisant pas les sessions.
  2. Pour toutes les requêtes entrantes POST ayant un cookie de session fixé, il vérifie que csrfmiddlewaretoken est présent et correcte. S’il ne l’est pas, l’utilisateur obtiendra une erreur HTTP 403. Le contenu de la page d’erreur 403 est le message «Cross Sote Request Forgery détecté. Requête annulée».

Ceci garanti que seul les formulaires originaires de votre site web peuvent être utilisés pour soumettre des données POST.

Ce middleware vise délibérément les seules requêtes HTTP POST ( et les formulaires POST correspondant). Comme nous l’avons expliqué, les requêtes GET ne devraient jamais avoir d’effet de bord; c’est à vous de vous en assurer.

Les requêtes POST qui ne sont pas accompagnées d’un cookie de session ne sont pas protégés, et n‘ont pas besoin de l’être, puisque un site web malicieux peut de toute façon faire ce type de requêtes.

Pour éviter d’altérer les requêtes non-HTML, le middleware vérifie la réponse Content-Type de l’en-tête avant de le modifier. Seules les pages qui sont servies comme text/html ou comme application/xml+xhtml sont modifiées.

Limitations of the CSRF Middleware

CsrfMiddleware à besoin du framework de session de Django pour fonctionner. (Lisez le chapitre 12 pour plus de détails sur les sessions). Si vous utilisez une session personnalisée ou un framework d’identification qui gère manuellement les cookies de session, ce middleware ne vous aidera pas.

Si votre application crée des pages HTML et des formulaires inhabituels (par exemple, s’il envoie des fragments de HTML dans une instruction Javascript document.write), vous devrez traverser le filtre qui ajoute le champ caché au formulaire. Dans ce cas, la soumission du formulaire échouera toujours. (Ceci arrive parce que CsrfMiddleware utilise une expression rationelle pour ajouter le champ csrfmiddlewaretoken à votre HTML avant que la page soit envoyée au client, et qu’une expression rationnelle peut parfois ne pas gérer du HTML farfelu). Si vous suspectez que cela puisse arriver, regardez simplement les sources dans votre navigateur internet pour voir si csrfmiddlewaretoken à été inséré dans votre <form>.

Pour plus d’information et d’exemples au sujet de CSRF, visitez http://en.wikipedia.org/wiki/CSRF.

Humaniser les données

Cette application propose un jeu de filtres de gabarit Django utiles pour ajouter une «touche humaine» aux données. Pour activer ces filtres, ajoutez 'django.contrib.humanize' à votre paramètre INSTALLED_APPS. Une fois que vous avez fait cela, utilisez {% load humanize %} dans un gabarit, et vous aurez acces aux filtres décrits dans les sections suivantes.

apnumber

Pour les nombres allant de 1 à 9, ce filtre renvoie la forme litérale du nombre. Sinon, il retourne le numéral. Ceci suit le style Associated Press.

Exemples:

  • 1 devient «one».
  • 2 devient «two».
  • 10 devient «10».

Vous pouvez lui passer soit un entier ou une représentation d’un entier sous forme de chaîne de caractère.

intcomma

Ce filtre converti un entier en une chaîne contenant des virgules tous les trois chiffres.

Exemples:

  • 4500 devient «4,500».
  • 45000 devient «45,000».
  • 450000 devient «450,000».
  • 4500000 devient «4,500,000».

Vous pouvez passer soit un entier soit une représentation d’un entier sous forme de chaîne.

intword

Ce filtre converti un grand entier en une représentation textuelle familière. Il fonctionne mieux pour les nombres au-delà du million.

Exemples:

  • 1000000 devient «1.0 million».
  • 1200000 devient «1.2 million».
  • 1200000000 devient «1.2 billion».

Les valeur au-delà du quadrillion (1,000,000,000,000,000) sont supportées.

Vous pouvez passer soit un entier soit une représentation d’un entier sous forme de chaîne.

ordinal

Ce filtre converti un entier en sont ordinal sous forme de chaîne.

Exemples:

  • 1 devient «1st».
  • 2 devient «2nd».
  • 3 devient «3rd».

Vous pouvez passer soit un entier soit une représentation d’un entier sous forme de chaîne.

Filtre de balisage

La collection de filtres de gabarit suivante implémente les langages de balisage courants:

Dans chaque cas, le filtre attends des balises formatées sousforme de chaîne et renvoie une chaîne représetant le texte balisé. Par exemple, le filtre textile converti le texte qui est balisé au format Textile en HTML:

{% load markup %}
{{ object.content|textile }}

Pour activer ces filtres, ajoutez 'django.contrib.markup' à votre paramètre INSTALLED_APPS. Lorsque vous avez fait cela, utilisez {% load markup %} dans un gabarit, et vous aurez accès à ces filtres. Pour plus de documentation, lisez le code source dans django/contrib/markup/templatetags/markup.py.

Et ensuite ?

Beaucoup de ces sous-frameworks contributifs (le CSRF, le système d’identification, etc.) opèrent leur magie en fournissant une partie de middleware. Middleware est essentiellement du code qui opère avant ou après chaque requête unique et qui peut modifier chaque requête et chaque réponse à la volée. Ensuite, nous discuterons des primitives middleware de Django et expliquerons coment vous pouvez en écrire par vous même.

<< précédentsuivant >>

Dernière modification: 2008-08-05 15:14:47.695990