diff options
| author | Chris McDonough <chrism@plope.com> | 2010-12-19 04:31:15 -0500 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2010-12-19 04:31:15 -0500 |
| commit | 70dacbbfbad1f0a3a3485e3104df191d7d3a8cc7 (patch) | |
| tree | 85621cc83b86fd858a9dc065c406de48f9bc1a61 | |
| parent | 780999e8504d1087d4e48a822174ebb69309bcfe (diff) | |
| download | pyramid-70dacbbfbad1f0a3a3485e3104df191d7d3a8cc7.tar.gz pyramid-70dacbbfbad1f0a3a3485e3104df191d7d3a8cc7.tar.bz2 pyramid-70dacbbfbad1f0a3a3485e3104df191d7d3a8cc7.zip | |
get rid of UNIX user analogy
| -rw-r--r-- | docs/narr/resourcelocation.rst | 109 | ||||
| -rw-r--r-- | docs/narr/traversal.rst | 117 |
2 files changed, 145 insertions, 81 deletions
diff --git a/docs/narr/resourcelocation.rst b/docs/narr/resourcelocation.rst new file mode 100644 index 000000000..aa8eaf23a --- /dev/null +++ b/docs/narr/resourcelocation.rst @@ -0,0 +1,109 @@ +.. index:: + single: resource location + +.. _resourcelocation_chapter: + +Resource Location and View Lookup +--------------------------------- + +As a primary job, :app:`Pyramid` provides a mechanism to find and invoke code +written by the application developer based on parameters present in the +:term:`request`. + +:app:`Pyramid` uses two separate but cooperating subsystems to find and +invoke code written by the application developer: :term:`resource location` +and :term:`view lookup`. + +- A :app:`Pyramid` :term:`resource location` subsystem is given a + :term:`request`; it is responsible for finding a :term:`resource` object + based on information present in the request. When a resource is found via + resource location, it becomes known as the :term:`context`. + +- Using the context provided by :term:`resource location`, the :app:`Pyramid` + :term:`view lookup` subsystem is provided with a :term:`request` and + :term:`context`. It is then responsible for finding and invoking a + :term:`view callable`. A view callable is a specific bit of code written + and registered by the application developer which receives the + :term:`request` and which returns a :term:`response`. + +These two subsystems are used by :app:`Pyramid` serially: first, a +:term:`resource location` subsystem does its job. Then the result of context +finding is passed to the :term:`view lookup` subsystem. The view lookup +system finds a :term:`view callable` written by an application developer, and +invokes it. A view callable returns a :term:`response`. The response is +returned to the requesting user. + +.. sidebar:: What Good is A Resource Location Subsystem? + + The :term:`URL dispatch` mode of :app:`Pyramid` as well as many other web + frameworks such as :term:`Pylons` or :term:`Django` actually collapse the + two steps of resource location and view lookup into a single step. In + these systems, a URL can map *directly* to a view callable. This makes + them simpler to understand than systems which use distinct subsystems to + locate a resource and find a view. However, explicitly finding a resource + provides extra flexibility. For example, it makes it possible to protect + your application with declarative context-sensitive instance-level + :term:`authorization`, which is not well-supported in frameworks that do + not provide a notion of a resource. + +There are two separate :term:`resource location` subsystems in +:app:`Pyramid`: :term:`traversal` and :term:`URL dispatch`. They can be used +separately or they can be combined. Three chapters which follow describe +:term:`resource location`: :ref:`traversal_chapter`, +:ref:`urldispatch_chapter` and :ref:`hybrid_chapter`. + +There is only one :term:`view lookup` subsystem present in :app:`Pyramid`. +Where appropriate, we will describe how view lookup interacts with context +finding. One chapter which follows describes :term:`view lookup`: +:ref:`views_chapter`. + +Should I Use Traversal or URL Dispatch for Resource Location? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since :app:`Pyramid` provides support for both approaches, you can use either +exclusively or combine them as you see fit. + +:term:`URL dispatch` is very straightforward. When you limit your +application to using URL dispatch, you know every URL that your application +might generate or respond to, all the URL matching elements are listed in a +single place, and you needn't think about :term:`resource location` or +:term:`view lookup` at all. + +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 single member in some system. +You just match everything "below" ``members`` to a particular :term:`view +callable`, e.g. ``/members/{memberid}``. + +However, URL dispatch is not very convenient if you'd like your URLs to +represent an arbitrary hierarchy. For example, if you need to infer the +difference between sets of URLs such as these, where the ``document`` in the +first URL represents a PDF document, and ``/stuff/page`` in the second +represents an OpenOffice document in a "stuff" folder. + +.. code-block:: text + + http://example.com/members/Chris/document + http://example.com/members/Chris/stuff/page + +It takes more pattern matching assertions to be able to make hierarchies work +in URL-dispatch based systems, and some assertions just aren't possible. +Essentially, URL-dispatch based systems just don't deal very well with URLs +that represent arbitrary-depth hierarchies. + +But :term:`traversal` *does* work well for URLs that represent +arbitrary-depth hierarchies. Since the path segments that compose a URL are +addressed separately, it becomes very easy to form URLs that represent +arbitrary depth hierarchies in a system that uses traversal. When you're +willing to treat your application resources as a tree that can be traversed, +it also becomes easy to provide "instance-level security": you just attach a +security declaration to each resource in the tree. This is not nearly as +easy to do when using URL dispatch. + +In essence, the choice to use traversal vs. URL dispatch is largely +religious. Traversal dispatch probably just doesn't make any sense when you +possess completely "square" data stored in a relational database because it +requires the construction and maintenance of a tree and requires that the +developer think about mapping URLs to code in terms of traversing that tree. +However, when you have a hierarchical data store, using traversal can provide +significant advantages over using URL-based dispatch. diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst index 98a009341..6510f3555 100644 --- a/docs/narr/traversal.rst +++ b/docs/narr/traversal.rst @@ -13,73 +13,27 @@ explain the concept of a resource tree, and we'll show how traversal might be used within an application. .. index:: - single: traversal analogy - -A Traversal Analogy -------------------- - -We use an analogy to provide an introduction to :term:`traversal`. -Imagine an inexperienced UNIX computer user, wishing only to use the -command line to find a file and to invoke the ``cat`` command against -that file. Because he is inexperienced, the only commands he knows -how to use are ``cd``, which changes the current directory and -``cat``, which prints the contents of a file. And because he is -inexperienced, he doesn't understand that ``cat`` can take an absolute -path specification as an argument, so he doesn't know that you can -issue a single command command ``cat /an/absolute/path`` to get the -desired result. Instead, this user believes he must issue the ``cd`` -command, starting from the root, for each intermediate path segment, -*even the path segment that represents the file itself*. Once he gets -an error (because you cannot successfully ``cd`` into a file), he -knows he has reached the file he wants, and he will be able to execute -``cat`` against the resulting path segment. - -This inexperienced user's attempt to execute ``cat`` against the file -named ``/fiz/buz/myfile`` might be to issue the following set of UNIX -commands: - -.. code-block:: text - - cd / - cd fiz - cd buz - cd myfile - -The user now knows he has found a *file*, because the ``cd`` command -issues an error when he executed ``cd myfile``. Now he knows that he -can run the ``cat`` command: - -.. code-block:: text - - cat myfile - -The contents of ``myfile`` are now printed on the user's behalf. - -:app:`Pyramid` is very much like this inexperienced UNIX user as it uses -:term:`traversal` against a resource tree. In this analogy, we can map the -``cat`` program to the :app:`Pyramid` concept of a :term:`view callable`: it -is a program that can be run against some :term:`resource` (the "context") as -the result of :term:`view lookup`. The file being operated on in this -analogy is the :term:`context` resource; the context is the "last resource -found" in a traversal. The directory structure is the resource tree being -traversed. The act of progressively changing directories to find the file as -well as the handling of a ``cd`` error as a stop condition is analogous to -:term:`traversal`. - -The analogy we've used is not *exactly* correct, because, while the naive -user already knows which command he wants to invoke before he starts -"traversing" (``cat``), :app:`Pyramid` needs to obtain that information from -the path being traversed itself. In :term:`traversal`, the "command" meant -to be invoked is a :term:`view callable`. A view callable is derived via -:term:`view lookup` from the combination of the :term:`request` and the -:term:`context`. - -.. index:: single: traversal overview A High-Level Overview of Traversal ---------------------------------- +A :term:`traversal` uses the URL (Universal Resource Locator) to find a +:term:`resource`. This is done by mapping each segment of the path portion +of the URL into a set of nested dictionary-like objects called the +:term:`resource tree`. You might think of this as looking up files and +directories in a file system. Traversal walks down the path until it finds a +published "directory" or "file". The resource we find as the result of a +traversal becomes the :term:`context`. A separate :term:`view lookup` +subsystem is used to then find some code willing "publish" the context +resource. + +.. index:: + single: traversal details + +Traversal Details +----------------- + :term:`Traversal` is dependent on information in a :term:`request` object. Every :term:`request` object contains URL path information in the ``PATH_INFO`` portion of the :term:`WSGI` environment. The ``PATH_INFO`` @@ -149,14 +103,15 @@ The Resource Tree ----------------- When your application uses :term:`traversal` to resolve URLs to code, your -application must supply the a resource tree to :app:`Pyramid`. This tree is -represented by a :term:`root` resource. +application must supply a :term:`resource tree` to :app:`Pyramid`. The +resource tree is a set of nested dictionary-like objects. The root of the +tree is represented by a :term:`root` resource. In order to supply a root resource for an application, at system startup -time, the :app:`Pyramid` :term:`Router` is configured with a -callback known as a :term:`root factory`. The root factory is -supplied by the application developer as the ``root_factory`` argument -to the application's :term:`Configurator`. +time, the :app:`Pyramid` :term:`Router` is configured with a callback known +as a :term:`root factory`. The root factory is supplied by the application +developer as the ``root_factory`` argument to the application's +:term:`Configurator`. Here's an example of a simple root factory: @@ -167,9 +122,8 @@ Here's an example of a simple root factory: def __init__(self, request): pass -Here's an example of using this root factory within startup -configuration, by passing it to an instance of a :term:`Configurator` -named ``config``: +Here's an example of using this root factory within startup configuration, by +passing it to an instance of a :term:`Configurator` named ``config``: .. code-block:: python :linenos: @@ -187,13 +141,13 @@ A root factory is passed a :term:`request` object and it is expected to return a resource which represents the root of the resource tree. All :term:`traversal` will begin at this root resource. Usually a root factory for a traversal-based application will be more complicated than the above -``Root`` class; in particular it may be associated with a database -connection or another persistence mechanism. +``Root`` class; in particular it may be associated with a database connection +or another persistence mechanism. If no :term:`root factory` is passed to the :app:`Pyramid` -:term:`Configurator` constructor, or the ``root_factory`` is specified -as the value ``None``, a *default* root factory is used. The default -root factory always returns a resource that has no child resources. +:term:`Configurator` constructor, or the ``root_factory`` is specified as the +value ``None``, a *default* root factory is used. The default root factory +always returns a resource that has no child resources. .. sidebar:: Emulating the Default Root Factory @@ -226,11 +180,12 @@ root factory always returns a resource that has no child resources. The resource tree consists of *container* resources and *leaf* resources. There is only one difference between a *container* resource and a *leaf* -resource: *container* resources possess a ``__getitem__`` method while *leaf* -resources do not. The ``__getitem__`` method was chosen as the signifying -difference between the two types of resources because the presence of this -method is how Python itself typically determines whether a resource is -"containerish" or not. +resource: *container* resources possess a ``__getitem__`` method (making it +"dictionary-like") while *leaf* resources do not. The ``__getitem__`` method +was chosen as the signifying difference between the two types of resources +because the presence of this method is how Python itself typically determines +whether an object is "containerish" or not (dictionary objects are +"containerish"). Each container resource is presumed to be willing to return a child resource or raise a ``KeyError`` based on a name passed to its ``__getitem__``. |
