summaryrefslogtreecommitdiff
path: root/docs/narr/urldispatch.rst
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2010-01-16 07:36:12 +0000
committerChris McDonough <chrism@agendaless.com>2010-01-16 07:36:12 +0000
commit590fe7c48d15f6280955e9784a9f42c2e28bca69 (patch)
tree65667668a46ba05d1902c7a8e18676f9399816ed /docs/narr/urldispatch.rst
parentc2441d669f52e79960ff63af134924da69b9afc1 (diff)
downloadpyramid-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.rst649
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`.
+