diff options
| author | Chris McDonough <chrism@agendaless.com> | 2010-01-16 07:36:12 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2010-01-16 07:36:12 +0000 |
| commit | 590fe7c48d15f6280955e9784a9f42c2e28bca69 (patch) | |
| tree | 65667668a46ba05d1902c7a8e18676f9399816ed /docs/narr/urldispatch.rst | |
| parent | c2441d669f52e79960ff63af134924da69b9afc1 (diff) | |
| download | pyramid-590fe7c48d15f6280955e9784a9f42c2e28bca69.tar.gz pyramid-590fe7c48d15f6280955e9784a9f42c2e28bca69.tar.bz2 pyramid-590fe7c48d15f6280955e9784a9f42c2e28bca69.zip | |
Massive overhaul to deal with the reality that we don't map URLs directly to code.
Diffstat (limited to 'docs/narr/urldispatch.rst')
| -rw-r--r-- | docs/narr/urldispatch.rst | 649 |
1 files changed, 413 insertions, 236 deletions
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index 699d017c4..44515cd54 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -6,61 +6,77 @@ URL Dispatch ============ -It is common for :mod:`repoze.bfg` developers to rely on -:term:`traversal` to map URLs to code. However, :mod:`repoze.bfg` can -also map URLs to code via :term:`URL dispatch`. The presence of -``<route>`` statements in a :term:`ZCML` file used by your application -or the presence of calls to the +The URL dispatch feature of :mod:`repoze.bfg` allows you to either +augment or replace :term:`traversal` as a :term:`context finding` +mechanism, allowing URL pattern matching to have the "first crack" at +resolving a given URL to :term:`context` and :term:`view name`. + +Using URL dispatch exclusively allows you to avoid thinking about your +application in terms of "contexts" and "view names" entirely. Many +applications don't need :mod:`repoze.bfg` features -- such as +declarative security via an :term:`authorization policy` -- that +benefit from having any visible separation between :term:`context +finding` and :term:`view lookup`. To this end, URL dispatch provides +a handy syntax that allows you to effectively map URLs *directly* to +:term:`view` code in such a way that you needn't think about your +application in terms "context finding" at all. This makes developing +a :mod:`repoze.bfg` application seem more like developing an +application in a system that is "context-free", such as :term:`Pylons` +or :term:`Django`. + +Whether or not you care about "context", it often makes a lot of sense +to use :term:`URL dispatch` instead of :term:`traversal` in an +application that has no natural data hierarchy. For instance, if all +the data in your application lives in a relational database, and that +relational database has no self-referencing tables that form a natural +hierarchy, URL dispatch is easier to use than traversal, and is often +a more natural fit for creating an application that manipulates "flat" +data. + +The presence of :ref:`route_directive` statements in a :term:`ZCML` +file used by your application or the presence of calls to the :meth:`repoze.bfg.configuration.Configurator.add_route` method in imperative configuration within your application is a sign that you're -using URL dispatch. Using the ``add_route`` configurator method or -``<route>`` statements in ZCML allows you to declaratively map URLs to -code. The syntax of the pattern matching language used by -:mod:`repoze.bfg` is close to that of :term:`Routes`. - -It often makes a lot of sense to use :term:`URL dispatch` instead of -:term:`traversal` in an application that has no natural hierarchy. -For instance, if all the data in your application lives in a -relational database, and that relational database has no -self-referencing tables that form a natural hierarchy, URL dispatch is -easier to use than traversal, and is often a more natural fit for -creating an application that manipulates "flat" data. - -Concept and Usage ------------------ - -The URL dispatch features of :mod:`repoze.bfg` allow you to either -augment or replace :term:`traversal`, allowing URL dispatch to have -the "first crack" (and potentially the *only* crack) at resolving a -given URL to :term:`context` and :term:`view name`. - -To allow for URL dispatch to be used, the :mod:`repoze.bfg` framework -allows you to inject ``route`` ZCML directives into your application's -``configure.zcml`` file. - -The :mod:`repoze.bfg` :term:`Router` checks an incoming request -against a *routes map* to find a :term:`context` and a :term:`view -callable` before :term:`traversal` has a chance to find these things -first. If a route matches, a :term:`context` is generated and -:mod:`repoze.bfg` will call the :term:`view callable` found due to the -context and the request. If no route matches, :mod:`repoze.bfg` will -fail over to calling the :term:`root factory` callable passed to the -:term:`Configurator` for the application (usually a traversal -function). - -A root factory is not required for purely URL-dispatch-based apps: if -the root factory callable is passed as ``None`` to the -:term:`Configurator`, :mod:`repoze.bfg` will return a :exc:`NotFound` -error to the user's browser when no routes match. - -.. note:: See :ref:`modelspy_project_section` for an example of a - simple root factory callable that will use traversal. +using :term:`URL dispatch`. + +High-Level Operational Overview +------------------------------- + +If route configuration is present in an application, the +:mod:`repoze.bfg` :term:`Router` checks every incoming request against +an ordered set of URL matching patterns present in a *route map*. + +If any route patern matches the information in the :term:`request` +provided to :mod:`repoze.bfg`, a route-specific :term:`context` and +:term:`view name` will be generated. In this circumstance, +:mod:`repoze.bfg` will shortcut :term:`traversal`, and will invoke +:term:`view lookup` using the context and view name generated by URL +dispatch. If the route named a :term:`view callable` in its +configuration, that view callable will be invoked when view lookup is +performed. + +However, if no route pattern matches the information in the +:term:`request` provided to :mod:`repoze.bfg`, it will fail over to +using :term:`traversal` to perform context finding and view lookup. + +Route Configuration +------------------- + +:term:`route configuration` is the act of adding a new :term:`route` +to an application. A route has a *path*, representing a pattern meant +to match against the ``PATH_INFO`` portion of a URL, and a *name*, +which is used by developers within a :mod:`repoze.bfg` application to +uniquely identify a particular route when generating a URL. It also +optionally has a ``factory`` and a set of :term:`view` parameters. + +A route configuration may be added to the system via :term:`imperative +configuration` or via :term:`ZCML`. Both are completely equivalent. .. index:: single: add_route -Configuring a Route via The ``add_route`` Configurator Method -------------------------------------------------------------- +Configuring a Route Imperatively via The ``add_route`` Configurator Method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The :meth:`repoze.bfg.configuration.Configurator.add_route` method adds a single :term:`route configuration` to the :term:`application @@ -69,13 +85,17 @@ registry`. Here's an example: .. ignore-next-block .. code-block:: python - config.add_route('myroute', '/prefix/:one/:two') + # "config" below is presumed to be an instance of the + # repoze.bfg.configuration.Configurator class; "myview" is assumed + # to be a "view callable" function + from views import myview + config.add_route(name='myroute', path='/prefix/:one/:two', view=myview) .. index:: single: ZCML directive; route Configuring a Route via ZCML ----------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Instead of using the imperative method of adding a route, you can use :term:`ZCML` for the same purpose. For example: @@ -86,82 +106,113 @@ Instead of using the imperative method of adding a route, you can use <route name="myroute" path="/prefix/:one/:two" + view=".views.myview" /> -See :ref:`route_directive` for full ``route`` ZCML directive -documentation. +.. note:: -.. note:: The documentation that follows in this chapter assumes that - :term:`ZCML` will be used to perform route configuration. + Values prefixed with a period (``.``) within the values of ZCML + attributes such as the ``view`` attribute of a ``route`` mean + "relative to the Python package directory in which this + :term:`ZCML` file is stored". So if the above ``route`` + declaration was made inside a ``configure.zcml`` file that lived in + the ``hello`` package, you could replace the relative + ``.views.myview`` with the absolute ``hello.views.myview`` Either + the relative or absolute form is functionally equivalent. It's + often useful to use the relative form, in case your package's name + changes. It's also shorter to type. -.. index:: - pair: route; ordering - -Route Ordering --------------- -ZCMl ``<route>`` declaration ordering and the ordering of calls to -:mod:`repoze.bfg.configuration.Configurator.add_route` is very -important, because routes are evaluated in a specific order. The -order that routes are evaluated is the order in which they are added -to the application at startup time. For ZCML, the order that routes -are evaluated is the order in which they appear in the ZCML relative -to each other. +See :ref:`route_directive` for full ``route`` ZCML directive +documentation. -This is unlike traversal, which depends on emergent behavior rather -than an ordered list of declarations. +Route Configuration That Names a View Callable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. index:: - pair: route; factory - single: route factory +When a route configuration declaration names a ``view`` attribute, the +attribute will be a value that references a :term:`view callable`. A +view callable, as described in :ref:`views_chapter`, is +developer-supplied code that "does stuff" as the result of a request. +For more information about how to create view callables, see +:ref:`views_chapter`. -Route Factories ---------------- - -A "route" declaration can mention a "factory". When a factory is -attached to a route, it is used to generate a root (it's a :term:`root -factory`) instead of the *default* root factory. This object will be -used as the :term:`context` of the view callable the route represents. +Here's an example route configuration that references a view callable: .. code-block:: xml + :linenos: <route - path="/abc" - name="abc" - view=".views.theview" - factory=".models.root_factory" + name="myroute" + path="/prefix/:one/:two" + view="mypackage.views.myview" /> -In this way, each route can use a different factory, making it -possible to supply a different :term:`context` object to the view -related to each route. - -.. index:: - pair: URL dispatch; matchdict - -The Matchdict -------------- - -The main purpose of a route is to match (nor not match) the -``PATH_INFO`` present in the WSGI environment provided during a -request against a URL path pattern. When this URL path pattern is -matched, a dictionary is placed on the request named ``matchdict`` -with the values that match patterns in the ``path`` element. If the -URL pattern does not match, no matchdict is generated. +When a route configuration names a ``view`` attribute, the :term:`view +callable` named as that ``view`` attribute will always be found and +invoked when the associated route path pattern matches during a +request. + +The purpose of making it possible to specify a view callable within a +route configuration is to avoid the need for developers to deeply +understand the details of :term:`context finding` and :term:`view +lookup`. When a route names a view callable, and a request enters the +system which matches the path of the route, the result is simple: the +view callable associated with the route is invoked with the request +that caused the invocation. + +For most usage, you needn't understand more than this; how it works is +an implementation detail. In the interest of completeness, however, +we'll explain how it *does* work in the following section. You can +skip it if you're uninterested. + +Route View Callable Registration and Lookup Details ++++++++++++++++++++++++++++++++++++++++++++++++++++ + +When a ``view`` attribute is attached to a route configuration, +:mod:`repoze.bfg` ensures that a :term:`view configuration` is +registered that will always be found when the route path pattern is +matched during a request. To do so: + +- A special route-specific :term:`interface` is created at startup time + for each route configuration declaration. + +- When a route configuration declaration mentions a ``view`` + attribute, a :term:`view configuration` is registered at startup + time. This view configuration uses the route-specific interface as + a :term:`request` type. + +- At runtime, when a request causes any route to match, the + :term:`request` object is decorated with the route-specific + interface. + +- The fact that the request is decorated with a route-specific + interface causes the view lookup machinery to always use the view + callable registered using that interface by the route configuration + to service requests that match the route path pattern. + +In this way, we supply a system that still consumes the :term:`context +finding` and :term:`view lookup` services provided by +:mod:`repoze.bfg`, but which does not require that a developer +understand either of them if he doesn't want to. It also means that +we can allow a developer to combine :term:`URL dispatch` and +:term:`traversal` in exceptional cases (see :ref:`hybrid_chapter`). .. index:: pair: URL dispatch; path pattern syntax .. _route_path_pattern_syntax: -Path Pattern Syntax --------------------- +Route Path Pattern Syntax +~~~~~~~~~~~~~~~~~~~~~~~~~ -The path pattern syntax is simple. +The syntax of the pattern matching language used by :mod:`repoze.bfg` +URL dispatch in the *path* argument is straightforward; it is close to +that of the :term:`Routes` system used by :term:`Pylons`. -The path may start with a slash character. If the path does not start -with a slash character, an implicit slash will be prepended to it at -matching time. For example, the following paths are equivalent: +The *path* used in route configuration may start with a slash +character. If the path does not start with a slash character, an +implicit slash will be prepended to it at matching time. For example, +the following paths are equivalent: .. code-block:: text @@ -264,81 +315,173 @@ Will generate the following matchdict: .. index:: triple: ZCML directive; route; examples -``<route>`` Statement Examples ------------------------------- -Let's check out some examples of how ``<route>`` statements might be -commonly declared. +.. index:: + pair: route; ordering + +Route Declaration Ordering +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Because route configuration declarations are evaluated in a specific +order when a request enters the system, route configuration +declaration ordering is very important. -Example 1 -~~~~~~~~~ +The order that routes declarations are evaluated is the order in which +they are added to the application at startup time. This is unlike +:term:`traversal`, which depends on the emergent behavior which +happens as a result of traversing a graph. + +For routes configured via ZCML, the order that routes are evaluated is +the order in which they appear in the ZCML relative to each other. +For routes added via the +:mod:`repoze.bfg.configuration.Configurator.add_route` method, the +order that routes are evaluated is the order in which they are added +to the configuration imperatively. -The simplest route declaration: +.. index:: + pair: route; factory + +Route Factories +~~~~~~~~~~~~~~~ + +A "route" configuration declaration can mention a "factory". When a +factory is attached to a route, the :term:`root factory` passed at +startup time to the :term:`Configurator` is ignored; instead the +factory associated with the route is used to generate a :term:`root` +object. This object will usually be used as the :term:`context` of +the view callable ultimately found via :term:`view lookup`. .. code-block:: xml - :linenos: <route - name="idea" - path="hello.html" - view="mypackage.views.hello_view" + path="/abc" + name="abc" + view=".views.theview" + factory=".models.root_factory" /> -When the URL matches ``/hello.html``, the view callable at the Python -dotted path name ``mypackage.views.hello_view`` will be called with a -default context object and the request. See :ref:`views_chapter` for -more information about views. +In this way, each route can use a different factory, making it +possible to supply a different :term:`context` object to the view +related to each particular route. -The ``mypackage.views`` module referred to above might look like so: +Supplying a different context for each route is useful when you're +trying to use a :mod:`repoze.bfg` :term:`authorization policy` to +provide declarative "context-sensitive" security checks; each context +can maintain a separate :term:`ACL` (as in +:ref:`using_security_with_urldispatch`). It is also useful when you +wish to combine URL dispatch with :term:`traversal` (as in +:ref:`hybrid_chapter`). -.. code-block:: python - :linenos: +Route Matching +-------------- - from webob import Response +The main purpose of route configuration is to match (nor not match) +the ``PATH_INFO`` present in the WSGI environment provided during a +request against a URL path pattern. - def hello_view(request): - return Response('Hello!') +The way that :mod:`repoze.bfg` does this is very simple. When a +request enters the system, for each route configuration declaration +present in the system, :mod:`repoze.bfg` checks the ``PATH_INFO`` +against the pattern declared. -.. note: the ``context`` attribute of the ``request`` object passed to - the above view will be an instance of the - :class:`repoze.bfg.urldispatch.DefaultRoutesContext` class. This - is the type of object created for a context when there is no - "factory" specified in the ``route`` declaration. It is a mapping - object, a lot like a dictionary. +If any route matches, the route matching process stops. The +:term:`request` is decorated with a special :term:`interface` which +describes it as a "route request", the :term:`context` and :term:`view +name` are generated, and the context, the view name, and the resulting +request are handed off to :term:`view lookup`. This process is +otherwise known as :term:`context finding`. During view lookup, if +any ``view`` argument was provided within the matched route +configuration, this view is called. -When using :term:`url dispatch` exclusively in an application (as -opposed to using both url dispatch and :term:`traversal`), the -:term:`context` of the view isn't always terribly interesting, -particularly if you never use a ``factory`` attribute on your route -definitions. However, if you do use a ``factory`` attribute on your -route definitions, you may be very interested in the :term:`context` -of the view. :mod:`repoze.bfg` supports view callables defined with -two arguments: ``context`` and ``request``. For example, the below -view statement is completely equivalent to the above view statement: +If no route matches after all route patterns are exhausted, +:mod:`repoze.bfg` falls back to :term:`traversal` to do :term:`context +finding` and :term:`view lookup`. + +.. index:: + pair: URL dispatch; matchdict + +The Matchdict +~~~~~~~~~~~~~ + +When the URL path pattern associated with a particular route +configuration is matched by a request, a dictionary named +``matchdict`` is added as an attribute of the :term:`request` object. +Thus, ``request.matchdict`` will contain the values that match +replacement patterns in the ``path`` element. The keys in a matchdict +will be strings. The values will be Unicode objects. + +.. note:: + + If no route URL pattern matches, no ``matchdict`` is attached to + the request. + +Routing Examples +---------------- + +Let's check out some examples of how route configuration statements +might be commonly declared, and what will happen if a they are matched +by the information present in a request. The examples that follow +assume that :term:`ZCML` will be used to perform route configuration, +although you can use :term:`imperative configuration` equivalently if +you like. + +.. _urldispatch_example1: + +Example 1 +~~~~~~~~~ + +The simplest route declaration which configures a route match to +*directly* result in a particular view callable being invoked: + +.. code-block:: xml + :linenos: + + <route + name="idea" + path="site/:id" + view="mypackage.views.site_view" + /> + +When a route configuration with a ``view`` attribute is added to the +system, and an incoming request matches the *path* of the route +configuration, the :term:`view callable` named as the ``view`` +attribute of the route configuration will be invoked. + +In the case of the above example, when the URL of a request matches +``/site/:id``, the view callable at the Python dotted path name +``mypackage.views.site_view`` will be called with the request. In +other words, we've associated a view callable directly with a route +path. + +When the ``/site/:id`` route path pattern matches during a request, +the ``site_view`` view callable is invoked with that request as its +sole argument. When this route matches, a ``matchdict`` will be +generated and attached to the request as ``request.matchdict``. If +the specific URL matched is ``/site/1``, the ``matchdict`` will be a +dictionary with a single key, ``id``; the value will be the string +``'1'``, ex.: ``{'id':'1'}``. + +The ``mypackage.views`` module referred to above might look like so: .. code-block:: python :linenos: from webob import Response - def hello_view(context, request): - return Response('Hello!') + def site_view(request): + return Response(request.matchdict['id']) -The ``context`` passed to this view will be an instance returned by -the default root factory or an instance returned by the ``factory`` -argument to your route definition. +The view has access to the matchdict directly via the request, and can +access variables within it that match keys present as a result of the +route path pattern. -Even if you use the request-only argument format in view callables, -you can still get to the ``context`` of the view (if necessary) by -accessing ``request.context``. - -See :ref:`request_and_context_view_definitions` for more information. +See :ref:`views_chapter` for more information about views. Example 2 ~~~~~~~~~ -Below is an example of some more complicated route statements you -might add to your ``configure.zcml``: +Below is an example of a more complicated set of route statements you +might add to your application: .. code-block:: xml :linenos: @@ -366,25 +509,46 @@ in these forms: .. code-block:: text - /ideas/<ideaname> - /users/<username> - /tags/<tagname> - -When a URL matches the pattern ``/ideas/<ideaname>``, the view -registered with the name ``idea`` will be called. This will be the -view available at the dotted Python pathname -``mypackage.views.idea_view``. + /ideas/:idea + /users/:user + /tags/:tag + +- When a URL matches the pattern ``/ideas/:idea``, the view available + at the dotted Python pathname ``mypackage.views.idea_view`` will be + called. For the specific URL ``/ideas/1``, the ``matchdict`` + generated and attached to the :term:`request` will consist of + ``{'idea':'1'}``. + +- When a URL matches the pattern ``/users/:user``, the view available + at the dotted Python pathname ``mypackage.views.user_view`` will be + called. For the specific URL ``/users/1``, the ``matchdict`` + generated and attached to the :term:`request` will consist of + ``{'user':'1'}``. + +- When a URL matches the pattern ``/tags/:tag``, the view available + at the dotted Python pathname ``mypackage.views.tag_view`` will be + called. For the specific URL ``/tags/1``, the ``matchdict`` + generated and attached to the :term:`request` will consist of + ``{'tag':'1'}``. + +In this example we've again associated each of our routes with a +:term:`view callable` directly. In all cases, the request, which will +have a ``matchdict`` attribute detailing the information found in the +URL by the process will be passed to the view callable. Example 3 ~~~~~~~~~ -The context object passed to a view found as the result of URL -dispatch will by default be an instance of the object returned by the -default :term:`root factory`. You can override this behavior by -passing in a ``factory`` argument to the ZCML directive for a -particular route. The ``factory`` should be a callable that accepts a -:term:`request` and returns an instance of a class that will be the -context used by the view. +The context object passed in to a view found as the result of URL +dispatch will, by default, be an instance of the object returned by +the :term:`root factory` configured at startup time (the +``root_factory`` argument to the :term:`Configurator` used to +configure the application). + +You can override this behavior by passing in a ``factory`` argument to +the ZCML directive for a particular route. The ``factory`` should be +a callable that accepts a :term:`request` and returns an instance of a +class that will be the context used by the view. An example of using a route with a factory: @@ -400,94 +564,67 @@ An example of using a route with a factory: The above route will manufacture an ``Idea`` model as a :term:`context`, assuming that ``mypackage.models.Idea`` resolves to a -class that accepts a request in its ``__init__``. - -.. note:: Values prefixed with a period (``.``) for the ``factory`` - and ``view`` attributes of a ``route`` (such as ``.models.Idea`` - and ``.views.idea_view``) above) mean "relative to the Python - package directory in which this :term:`ZCML` file is stored". So - if the above ``route`` declaration was made inside a - ``configure.zcml`` file that lived in the ``hello`` package, you - could replace the relative ``.models.Idea`` with the absolute - ``hello.models.Idea`` Either the relative or absolute form is - functionally equivalent. It's often useful to use the relative - form, in case your package's name changes. It's also shorter to - type. - -If no route matches in the above configuration, :mod:`repoze.bfg` will -call the "fallback" :term:`root factory` callable provided to the -:term:`Configurator` constructor. If the "fallback" root factory is -None, a :exc:`NotFound` error will be raised when no route matches. - -.. note:: See :ref:`using_model_interfaces` for more information about - how views are found when interfaces are attached to a - context. You can also map classes to views; interfaces are - not used then. +class that accepts a request in its ``__init__``. For example: + +.. code-block:: python + :linenos: + + class Idea(object): + def __init__(self, request): + pass + +In a more complicated application, this root factory might be a class +representing a :term:`SQLAlchemy` model. Example 4 ~~~~~~~~~ -An example of configuring a ``view`` declaration in ``configure.zcml`` -that maps a context found via URL dispatch to a view function is as -follows: +It is possible to create a route declaration without a ``view`` +attribute, but associate the route with a :term:`view callable` using +a ``view`` declaration. .. code-block:: xml :linenos: <route - name="article" - path="archives/:article" - view=".views.article_view" - factory=".models.Article" - /> - -The ``.models`` module referred to above might look like so: - -.. code-block:: python - :linenos: - - class Article(object): - def __init__(self, request): - self.__dict__.update(request.matchdict) + name="idea" + path="site/:id" + /> - def is_root(self): - return self.article == 'root' + <view + view="mypackage.views.site_view" + route_name="idea" + /> -The ``.views`` module referred to above might look like so: +This set of configuration parameters creates a configuration +completely equivalent to this example provided in +:ref:`urldispatch_example1`: -.. code-block:: python +.. code-block:: xml :linenos: - from webob import Response + <route + name="idea" + path="site/:id" + view="mypackage.views.site_view" + /> + +In fact the spelling in :ref:`urldispatch_example1` is just syntactic +sugar for the more verbose spelling where the route declaration and +the view declaration are spelled separately. - def article_view(context, request): - if context.is_root(): - return Response('Root article') - else: - return Response('Article with name %s' % context.article) - -The effect of this configuration: when this :mod:`repoze.bfg` -application runs, if any URL matches the pattern -``archives/:article``, the ``.views.articles_view`` view will be -called with its :term:`context` as a instance of the ``Article`` -class. The ``Article`` instance will have keys and values matching -the keys and values in the routing dictionary associated with the -request. - -In this case in particular, when a user visits -``/archives/something``, the context will be an instance of the -Article class and it will have an ``article`` attribute with the value -of ``something``. +More uses for this style of associating views with routes are explored +in :ref:`hybrid_chapter`. .. index:: - pair: URL dispatch; catching root URL + pair: URL dispatch; matching the root URL -Catching the Root URL +Matching the Root URL --------------------- -It's not entirely obvious how to use a route to catch the root URL -("/"). To do so, give the empty string as a path in a ZCML ``route`` -declaration: +It's not entirely obvious how to use a route path pattern to match the +root URL ("/"). To do so, give the empty string as a path in a ZCML +``route`` declaration: .. code-block:: xml :linenos: @@ -684,3 +821,43 @@ not very ambitious. .. note:: See :ref:`security_chapter` for more information about :mod:`repoze.bfg` security and ACLs. +Context-and-Request View Callables +---------------------------------- + +When using :term:`url dispatch` exclusively in an application (as +opposed to using both url dispatch *and* :term:`traversal` in the same +application), the :term:`context` of the view isn't always terribly +interesting, particularly if you never use a ``factory`` attribute on +your route definitions. + +However, if you do use a ``factory`` attribute on your route +definitions, you may be very interested in the :term:`context` of the +view. :mod:`repoze.bfg` supports view callables defined with two +arguments: ``context`` and ``request``. For example, the below view +statement is completely equivalent to the above view statement: + +.. code-block:: python + :linenos: + + from webob import Response + + def hello_view(context, request): + return Response('Hello!') + +The ``context`` passed to this view will be an instance returned by +the default root factory or an instance returned by the ``factory`` +argument to your route definition. + +Even if you use the request-only argument format in view callables, +you can still get to the ``context`` of the view (if necessary) by +accessing ``request.context``. + +See :ref:`request_and_context_view_definitions` for more information. + +References +---------- + +For a contextual example of how :term:`URL dispatch` can be used to +create a :mod:`repoze.bfg` application, see the +:ref:`bfg_sql_wiki_tutorial`. + |
