Le systeme de routes de pyramid

Le dans «fr python» par Cyprien Le Pannérer
Mots-clés:

Introduction

pyramid utilise un système de routes prédéclarées dans le fichier __init__.py (appelé url dispatch dans la documentation). Pyramid permet également les urls traversal mais ce sera pour une autre fois.

Les routes sont déclarées par un couple : le nom de la route et un motif. ex :

config.add_route('home', '/')

Ici home est le nom de la route et / est le motif correspondant à la racine du site. config.add_route rajoute la route home au registre de l'application.

Les motifs

Les motifs décrivent les chemins du site web. ex:

  • /
  • /foo
  • /foo/bar

config.add_route('foo', '/foo') est strictement équivalent à config.add_route('foo', 'foo').

Le / de fin

config.add_route('foo', '/foo') est différent de config.add_route('foo', '/foo/')

config.add_route('foo1', '/foo')
config.add_route('foo2', '/foo/')

Les routes foo1 et foo2 sont deux routes différentes qui renverront vers deux vues différentes (sauf si on décore deux fois la même vue.).

pyramid fournit un mécanisme pour faire correpondre /foo à /foo/ mais l'inverse n'est pas possible (Je pense que c'est possible au prix d'un petit dev dans les entrailles de pyramid.).

# exemple pris dans la doc officielle de pyramid.

from pyramid.httpexceptions import HTTPNotFound

def notfound(request):
    return HTTPNotFound('Not found, bro.')

def has_slash(request):
    return Response('Has slash')

def main(g, **settings):
    config = Configurator()

    config.add_route('hasslash', 'has_slash/')
    config.add_view(has_slash, route_name='hasslash')

    config.add_notfound_view(notfound, append_slash=True)

Dans cet exemple, le chemin has_slash renverra sur has_slash. Ceci se fait en définissant la vue 404 not found dans la dernière ligne en demandant de rajouter / s'il est manquant. S'il n'y a toujours pas de route correspondant à ce chemin la fonction notfound correspondant à la 404 sera appelée et levera l'exception HTTPNotFound.

Note

les exceptions pyramid sont identique à celle de WebOb

Les variables

Les motifs décrivant les routes peuvent contenir des variables pour décrire des chemins et les variables peuvent être récupérer via l'objet request :

  • /user/{id}
  • /user/{id}/contacts
  • /user/{id}/contacts/{contact}
  • /foo/{bar}/{baz}

ces motifs peuvent faire matcher les chemins suivants :

  • /user/1
  • /user/2
  • /user/a
  • /user/a/contacts
  • [...]

Les parties entre accolades sont contenus dans des variables donc l'accès sera décrit plus tard. Les motifs peuvent également contenir des expressions rationnelles :

  • /user/{id:d*}
  • /user/{id:w{4}}

Les urls ne seront matchées que si elles correspondent aux motifs. Ces expressions rationnelles permettent également d'avoir des routes différentes pour des url similaires:

config.add_route('userDigit', '/user/{id:\d*}')
config.add_route('userAlpha', '/user/{id:\w*}')

La première route correspondera à /user/1232445 et la seconde à /user/azerty. Les 2 routes pourront être gérées différement selon les views.

Les variables définies dans les motifs sont récupérable via l'objet request.

from pyramid.httpexceptions import HTTPNotFound


def foo(request):
    return Response('foo %s' % str(request.matchdict['bar']))

def main(g, **settings):
    config = Configurator()

    config.add_route('foo', '/foo/{bar}')
    config.add_view(foo, route_name='foo')

Le chemin /foo/baz renverra la page contenant foo baz.

Les variables ne sont pas nécéssairement un élément du path :

config.add_route('foo', '/{foo}/{bar}.html')
config.add_route('baz', '/{foo}/{bar}.{extention}')

Les conflits

L'ordre de déclaration des routes à une importance car les routes peuvent générer des conflits entre elles.

config.add_route('userAlpha', '/user/{id:\w*}')
config.add_route('user4Alpha', '/user/{id:\w{4}}')

La route userAlpha étant déclarée avant user4Alpha, toutes les requêtes seront dirigées vers la route userAlpha.

config.add_route('user4Alpha', '/user/{id:\w{4}}')
config.add_route('userAlpha', '/user/{id:\w*}')

Dans l'exemple ci dessus, il n'y a plus de conflits ; les chemins avec exactement 4 lettres seront dirigés vers user4Alpha et les autres vers userAlpha.

autre exemple de conflits potentiels:

config.add_route('foobar', '/foo/{bar}')
config.add_route('foobaz', '/foo/baz')

Un nombre indéterminé de variables

Il est bien entendu possible d'avoir plus d'une variable dans le path.

config.add_route('foobar', '/{foo}/{bar}')

Ici, nous aurons 2 variables foo et bar.

Si nous voulons une url avec un nombre indéterminée de sous parties :

config.add_route('foobar', '/{foo}/{bar}*baz')

Cette route matchera :

  • /plop/plip
  • /plop/plip/
  • /plop/plip/a
  • /plop/plip/a/b/c/d/

Dans ces chemins, foo et bar contientront respectivement 'plop' et 'plip'. baz condientra selon les chemins :

  • (),
  • (),
  • (u'a'),
  • (u'a, u'b', u'c', u'd')

Conclusion

Pyramid nous offre un sytème simple et puissant de dispatch d'url via les routes. Il existe d'autre système d'url comme traversal url (que j'essairai d'aborder une prochaine fois) ou par controler successif comme pyramid_controllers.

Quelques liens vers la documentation de pyramid: