summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2008-07-31 07:47:43 +0000
committerChris McDonough <chrism@agendaless.com>2008-07-31 07:47:43 +0000
commit39b8b920c8018dc4d124cba72794da1dcc925cce (patch)
treef8668c1f76fc545edce9703f089575bcde8f7b31
parent3ca90c8b8bad255a286b412a94dabfb501e6d59a (diff)
downloadpyramid-39b8b920c8018dc4d124cba72794da1dcc925cce.tar.gz
pyramid-39b8b920c8018dc4d124cba72794da1dcc925cce.tar.bz2
pyramid-39b8b920c8018dc4d124cba72794da1dcc925cce.zip
More balance between URL dispatch and traversal.
-rw-r--r--docs/glossary.rst3
-rw-r--r--docs/index.rst2
-rw-r--r--docs/narr/traversal.rst127
-rw-r--r--docs/narr/urldispatch.rst14
-rw-r--r--docs/narr/urlmapping.rst99
5 files changed, 160 insertions, 85 deletions
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 385cc7f24..f1ccf1575 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -159,6 +159,9 @@ Glossary
Zope
`The Z Object Publishing Framework <http://zope.org>`_. The granddaddy
of Python web frameworks.
+ ZODB
+ `Zope Object Database <http://wiki.zope.org/ZODB/FrontPage>`_, a
+ persistent Python object store.
WebOb
`WebOb <http://pythonpaste.org/webob/>`_ is a WSGI request/response
library created by Ian Bicking.
diff --git a/docs/index.rst b/docs/index.rst
index 63f8b96e4..3f20d0797 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -25,7 +25,9 @@ Narrative documentation in chapter form explaining how to use
narr/introduction
narr/install
narr/project
+ narr/urlmapping
narr/traversal
+ narr/urldispatch
narr/views
narr/templates
narr/models
diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst
index 673f94927..f03a22c9e 100644
--- a/docs/narr/traversal.rst
+++ b/docs/narr/traversal.rst
@@ -3,100 +3,57 @@
Traversal
=========
-In many popular web frameworks, :term:`URL dispatch` is used to
-associate a particular URL with a bit of code (known somewhat
-ambiguously as a "controller" or :term:`view` depending upon the
-particular vocabulary religion to which you subscribe). These systems
-allow the developer to create "urlconfs" or "routes" to
-controller/view Python code using pattern matching against URL
-components. Examples: `Django's URL dispatcher
-<http://www.djangoproject.com/documentation/url_dispatch/>`_ and the
-:term:`Routes` URL mapping system.
-
-:mod:`repoze.bfg` supports :term:`URL dispatch` via :term:`Routes`.
-See the :ref:`urldispatch_module` for more information about using URL
-dispatch.
-
-By default, however, :mod:`repoze.bfg` does not use URL dispatch to
-map URLs to code. Instead, it maps URLs to code slightly differently,
-using object graph :term:`traversal`. The venerable Zope and CherryPy
-web frameworks offer graph-traversal-based URL dispatch.
-Graph-traversal based dispatching is useful if you like the URL to
-represent an arbitrary hierarchy of potentially heterogeneous items.
-
-:term:`URL dispatch` can easily handle URLs such as
-``http://example.com/members/Chris``, where it's assumed that each
-item "below" ``members`` in the URL represents a member in the system.
-You just match everything "below" ``members`` to a particular view.
-They are not very good, however, at inferring the difference between
-sets of URLs such as::
-
- http://example.com/members/Chris/document
- http://example.com/members/Chris/stuff/page
-
-...wherein you'd like the ``document`` in the first URL to represent a
-PDF document, and ``/stuff/page`` in the second to represent an
-*OpenOffice* document in a "stuff" folder. It takes more pattern
-matching assertions to be able to make URLs like these work in
-URL-dispatch based systems, and some assertions just aren't possible.
-For example, URL-dispatch based systems don't deal very well with URLs
-that represent arbitrary-depth hierarchies.
-
-Graph :term:`traversal` works well if you need to divine meaning out
-of these types of "ambiguous" URLs and URLs that represent
-arbitrary-depth hierarchies. Each URL segment represents a single
-traversal through an edge of the graph. So a URL like
-``http://example.com/a/b/c`` can be thought of as a graph traversal on
-the example.com site through the edges ``a``, ``b``, and ``c``.
-
-Finally, if you're willing to treat your application models as a graph
-that can be traversed, it also becomes trivial to provide "row-level
-security" (in common relational parlance): you just attach a security
-declaration to each instance in the graph. This is not as easy in
-frameworks that use URL-based dispatch.
-
-Graph traversal is materially more complex than URL-based dispatch,
-however, if only because it requires the construction and maintenance
-of a graph, and it requires the developer to think about mapping URLs
-to code in terms of traversing the graph. (How's *that* for
-self-referential! ;-) ) That said, for developers comfortable with
-:term:`Zope` or comfortable with hierarchical data stores like *ZODB*
-or a filesystem, mapping a URL to a graph traversal is a natural way
-to think about creating a web application.
-
-In essence, the choice to use graph traversal vs. URL dispatch is
-largely religious in some sense. Graph traversal dispatch probably
-just doesn't make any sense when you possess completely "square" data
-stored in a relational database. However, when you have a
-hierarchical data store, it can provide advantages over using
-URL-based dispatch.
-
-:mod:`repoze.bfg` provides support for both approaches. Graph
-traversal is described in detail below.
+The :mod:`repoze.bfg` *Router* parses the URL associated with the
+request and traverses the graph based on path segments in the URL.
+Based on these path segments, :mod:`repoze.bfg` traverses the *model
+graph* in order to find a :term:`context`. It then attempts to find a
+:term:`view` based on the *type* of the context (specified by an
+:term:`interface`). If :mod:`repoze.bfg` finds a :term:`view` for the
+context, it calls it and returns a response to the user.
The Model Graph
---------------
+When your application uses :term:`traversal` to resolve URLs to code,
+your application must supply a *model graph* to :mod:`repoze.bfg`.
+
Users interact with your :mod:`repoze.bfg` -based application via a
-"router", which is itself a WSGI application. At system startup time,
-the router is configured with a root object from which all traversal
-will begin. The root object is usually a mapping object, such as a
-Python dictionary. Usually the root is a *container* node, and thus
-contains other items. In fact, all items contained in the graph are
-either *leaf* nodes (these have no ``__getitem__``) or *container*
-nodes (these do have a ``__getitem__``).
+*router*, which is just a fancy :term:`WSGI` application. At system
+startup time, the router is configured with a single object which
+represents the root of the model graph. All traversal will begin at
+this root object. The root object is usually a *mapping* object (such
+as a Python dictionary).
Items contained within the graph are analogous to the concept of
:term:`model` objects used by many other frameworks (and
:mod:`repoze.bfg` refers to them as models, as well). They are
-typically instances of Python classes. Each containerish instance is
-willing to return a child or raise a ``KeyError`` based on a name
-passed to its ``__getitem__``. No leaf-level instance is required to
-have a ``__getitem__``.
-
-:mod:`repoze.bfg` traverses the model graph in order to find a
-:term:`context`. It then attempts to find a :term`view` based on the
-type (specified by an :term:`interface`) of the context.
+typically instances of Python classes.
+
+The model graph consists of *container* nodes and *leaf* nodes. There
+is only one difference between *container* node and a *leaf* node:
+*container* nodes a ``__getitem__`` method while *leaf* nodes do not.
+The ``__getitem__`` method was chosen as the signifying difference
+between the two types of nodes because the presence of this method is
+how Python itself typically determines whether an object is
+"containerish" or not.
+
+A container node is presumed to be willing to return a child node or
+raise a ``KeyError`` based on a name passed to its ``__getitem__``.
+
+No leaf-level instance is required to have a ``__getitem__``. If
+leaf-level instances happen to have a ``__getitem__`` (through some
+historical inequity), you should subclass these node types and cause
+their ``__getitem__`` methods to simply raise a ``KeyError``. Or just
+disuse them and think up another strategy.
+
+Usually, the traversal root is a *container* node, and as such it
+contains other nodes. However, it doesn't *need* to be a container.
+Your model graph can be as shallow or as deep as you require.
+
+Traversal "stops" when :mod:`repoze.bfg` either reaches a leaf level
+model instance in your object graph or when the path segments implied
+by the URL "run out". The object that traversal "stops on" becomes
+the :term:`context`.
How :mod:`repoze.bfg` Processes a Request Using Traversal
---------------------------------------------------------
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
new file mode 100644
index 000000000..42413ca73
--- /dev/null
+++ b/docs/narr/urldispatch.rst
@@ -0,0 +1,14 @@
+.. _urldispatch_chapter:
+
+URL Dispatch
+============
+
+It is more common for :mod:`repoze.bfg` users to rely on
+:term:`traversal` to map URLs to code. However, :mod:`repoze.bfg` can
+also map URLs to code via :term:`URL dispatch` using the
+:term:`Routes` framework.
+
+Please see the :ref:`urldispatch_module` module API documentation for
+more information on using :term:`URL dispatch` with :mod:`repoze.bfg`.
+
+
diff --git a/docs/narr/urlmapping.rst b/docs/narr/urlmapping.rst
new file mode 100644
index 000000000..3c74d04d9
--- /dev/null
+++ b/docs/narr/urlmapping.rst
@@ -0,0 +1,99 @@
+.. _url_mapping_chapter:
+
+Mapping URLs to Code
+====================
+
+Many popular web frameworks today use :term:`URL dispatch` to
+associate a particular URL with a bit of code (known somewhat
+ambiguously as a "controller" or :term:`view` depending upon the
+particular vocabulary religion to which you subscribe). These systems
+allow the developer to create "urlconfs" or "routes" to
+controller/view Python code using pattern matching against URL
+components. Examples: `Django's URL dispatcher
+<http://www.djangoproject.com/documentation/url_dispatch/>`_ and the
+:term:`Routes` URL mapping system.
+
+:mod:`repoze.bfg` supports :term:`URL dispatch` via :term:`Routes`.
+:term:`URL dispatch` is convenient and straightforward. When you
+limit your application to using URL dispatch, you know every URL that
+your application might generate or respond to, and all the URL
+matching elements are listed in a single place.
+
+Like :term:`Zope`, :mod:`repoze.bfg`, in contrast to URL dispatch, can
+also map URLs to code slightly differently, by using using object
+graph :term:`traversal`. Graph-traversal based dispatching is useful
+if you like your URLs to represent an arbitrary hierarchy of
+potentially heterogeneous items, or if you need to attach
+"instance-level" security (akin to "row-level" security in relational
+parlance) declarations to :term:`model` instances.
+
+Differences Between Traversal and URL Dispatch
+----------------------------------------------
+
+:term:`URL dispatch` can easily handle URLs such as
+``http://example.com/members/Chris``, where it's assumed that each
+item "below" ``members`` in the URL represents a member in the system.
+You just match everything "below" ``members`` to a particular view.
+
+For example, you might configure a :term:`Routes` URL map to match
+against the following URL patterns::
+
+ archives/:year/:month/:day
+ members/:membername
+
+In this configuration, there are exactly two types of URLs that will
+match views in your application: ones that start with ``/archives``
+and have subsequent path elements that represent a year, month, and
+day. And ones that start with ``/members`` which are followed by a
+path segment containing a member's name. This is very simple.
+
+:term:`URL dispatch` is not very good, however, at inferring the
+difference between sets of URLs such as::
+
+ http://example.com/members/Chris/document
+ http://example.com/members/Chris/stuff/page
+
+...wherein you'd like the ``document`` in the first URL to represent a
+PDF document, and ``/stuff/page`` in the second to represent an
+*OpenOffice* document in a "stuff" folder. It takes more pattern
+matching assertions to be able to make URLs like these work in
+URL-dispatch based systems, and some assertions just aren't possible.
+For example, URL-dispatch based systems don't deal very well with URLs
+that represent arbitrary-depth hierarchies.
+
+Graph :term:`traversal` works well if you need to divine meaning out
+of these types of "ambiguous" URLs and URLs that represent
+arbitrary-depth hierarchies. Each URL segment represents a single
+traversal through an edge of the graph. So a URL like
+``http://example.com/a/b/c`` can be thought of as a graph traversal on
+the ``example.com`` site through the edges ``a``, ``b``, and ``c``.
+
+If you're willing to treat your application models as a graph that can
+be traversed, it also becomes easy to provide "row-level security" (in
+common relational parlance): you just attach a security declaration to
+each instance in the graph. This is not as easy in frameworks that
+use URL-based dispatch.
+
+Graph traversal is materially more complex than URL-based dispatch,
+however, if only because it requires the construction and maintenance
+of a graph, and it requires the developer to think about mapping URLs
+to code in terms of traversing the graph. (How's *that* for
+self-referential! ;-) )
+
+In essence, the choice to use graph traversal vs. URL dispatch is
+largely religious in some sense. Graph traversal dispatch probably
+just doesn't make any sense when you possess completely "square" data
+stored in a relational database. However, when you have a
+hierarchical data store, it can provide advantages over using
+URL-based dispatch.
+
+:mod:`repoze.bfg` provides support for both approaches. You can use
+either as you see fit.
+
+.. note::
+
+ Most existng :mod:`repoze.bfg` applications use :term:`traversal` to
+ map URLs to code. This is mostly due to the :term:`Zope` heritage
+ of :mod:`repoze.bfg` and because it aids applications that require
+ highly granular declarative security assertions.
+