diff options
| author | Steve Piercy <web@stevepiercy.com> | 2015-11-02 00:09:06 -0800 |
|---|---|---|
| committer | Steve Piercy <web@stevepiercy.com> | 2015-11-02 00:09:06 -0800 |
| commit | 50d32d442b81f0e06bf3eee034f7b2eb8cdfb2ec (patch) | |
| tree | abe37acc8c81a89074b69f1f467001b2f1deb100 /docs/narr/hybrid.rst | |
| parent | cfd8ccfce67b89fab9095ac41ac3ca85f9c0da0e (diff) | |
| download | pyramid-50d32d442b81f0e06bf3eee034f7b2eb8cdfb2ec.tar.gz pyramid-50d32d442b81f0e06bf3eee034f7b2eb8cdfb2ec.tar.bz2 pyramid-50d32d442b81f0e06bf3eee034f7b2eb8cdfb2ec.zip | |
- remove deprecated section in docs (Closes #2067)
- minor grammar, rewrap to 79 columns
Diffstat (limited to 'docs/narr/hybrid.rst')
| -rw-r--r-- | docs/narr/hybrid.rst | 539 |
1 files changed, 217 insertions, 322 deletions
diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst index 1c324d22b..ff26d52ec 100644 --- a/docs/narr/hybrid.rst +++ b/docs/narr/hybrid.rst @@ -12,28 +12,26 @@ dispatch. However, to solve a limited set of problems, it's useful to use .. warning:: Reasoning about the behavior of a "hybrid" URL dispatch + traversal - application can be challenging. To successfully reason about using - URL dispatch and traversal together, you need to understand URL - pattern matching, root factories, and the :term:`traversal` - algorithm, and the potential interactions between them. Therefore, - we don't recommend creating an application that relies on hybrid - behavior unless you must. + application can be challenging. To successfully reason about using URL + dispatch and traversal together, you need to understand URL pattern + matching, root factories, and the :term:`traversal` algorithm, and the + potential interactions between them. Therefore, we don't recommend creating + an application that relies on hybrid behavior unless you must. A Review of Non-Hybrid Applications ----------------------------------- -When used according to the tutorials in its documentation -:app:`Pyramid` is a "dual-mode" framework: the tutorials explain -how to create an application in terms of using either :term:`url -dispatch` *or* :term:`traversal`. This chapter details how you might -combine these two dispatch mechanisms, but we'll review how they work -in isolation before trying to combine them. +When used according to the tutorials in its documentation, :app:`Pyramid` is a +"dual-mode" framework: the tutorials explain how to create an application in +terms of using either :term:`URL dispatch` *or* :term:`traversal`. This +chapter details how you might combine these two dispatch mechanisms, but we'll +review how they work in isolation before trying to combine them. URL Dispatch Only ~~~~~~~~~~~~~~~~~ -An application that uses :term:`url dispatch` exclusively to map URLs to code -will often have statements like this within application startup +An application that uses :term:`URL dispatch` exclusively to map URLs to code +will often have statements like this within its application startup configuration: .. code-block:: python @@ -48,11 +46,11 @@ configuration: config.add_view('myproject.views.bazbuz', route_name='bazbuz') Each :term:`route` corresponds to one or more view callables. Each view -callable is associated with a route by passing a ``route_name`` parameter -that matches its name during a call to -:meth:`~pyramid.config.Configurator.add_view`. When a route is matched -during a request, :term:`view lookup` is used to match the request to its -associated view callable. The presence of calls to +callable is associated with a route by passing a ``route_name`` parameter that +matches its name during a call to +:meth:`~pyramid.config.Configurator.add_view`. When a route is matched during +a request, :term:`view lookup` is used to match the request to its associated +view callable. The presence of calls to :meth:`~pyramid.config.Configurator.add_route` signify that an application is using URL dispatch. @@ -72,12 +70,11 @@ declarations that look like this: When the above configuration is applied to an application, the ``mypackage.views.foobar`` view callable above will be called when the URL -``/foobar`` is visited. Likewise, the view ``mypackage.views.bazbuz`` will -be called when the URL ``/bazbuz`` is visited. +``/foobar`` is visited. Likewise, the view ``mypackage.views.bazbuz`` will be +called when the URL ``/bazbuz`` is visited. Typically, an application that uses traversal exclusively won't perform any -calls to :meth:`pyramid.config.Configurator.add_route` in its startup -code. +calls to :meth:`pyramid.config.Configurator.add_route` in its startup code. .. index:: single: hybrid applications @@ -85,149 +82,139 @@ code. Hybrid Applications ------------------- -Either traversal or url dispatch alone can be used to create a -:app:`Pyramid` application. However, it is also possible to -combine the concepts of traversal and url dispatch when building an -application: the result is a hybrid application. In a hybrid -application, traversal is performed *after* a particular route has -matched. - -A hybrid application is a lot more like a "pure" traversal-based -application than it is like a "pure" URL-dispatch based application. -But unlike in a "pure" traversal-based application, in a hybrid -application, :term:`traversal` is performed during a request after a -route has already matched. This means that the URL pattern that -represents the ``pattern`` argument of a route must match the -``PATH_INFO`` of a request, and after the route pattern has matched, -most of the "normal" rules of traversal with respect to :term:`resource -location` and :term:`view lookup` apply. +Either traversal or URL dispatch alone can be used to create a :app:`Pyramid` +application. However, it is also possible to combine the concepts of traversal +and URL dispatch when building an application, the result of which is a hybrid +application. In a hybrid application, traversal is performed *after* a +particular route has matched. + +A hybrid application is a lot more like a "pure" traversal-based application +than it is like a "pure" URL-dispatch based application. But unlike in a "pure" +traversal-based application, in a hybrid application :term:`traversal` is +performed during a request after a route has already matched. This means that +the URL pattern that represents the ``pattern`` argument of a route must match +the ``PATH_INFO`` of a request, and after the route pattern has matched, most +of the "normal" rules of traversal with respect to :term:`resource location` +and :term:`view lookup` apply. There are only four real differences between a purely traversal-based application and a hybrid application: -- In a purely traversal based application, no routes are defined; in a - hybrid application, at least one route will be defined. +- In a purely traversal-based application, no routes are defined. In a hybrid + application, at least one route will be defined. -- In a purely traversal based application, the root object used is - global, implied by the :term:`root factory` provided at startup - time; in a hybrid application, the :term:`root` object at which - traversal begins may be varied on a per-route basis. +- In a purely traversal-based application, the root object used is global, + implied by the :term:`root factory` provided at startup time. In a hybrid + application, the :term:`root` object at which traversal begins may be varied + on a per-route basis. -- In a purely traversal-based application, the ``PATH_INFO`` of the - underlying :term:`WSGI` environment is used wholesale as a traversal - path; in a hybrid application, the traversal path is not the entire - ``PATH_INFO`` string, but a portion of the URL determined by a - matching pattern in the matched route configuration's pattern. +- In a purely traversal-based application, the ``PATH_INFO`` of the underlying + :term:`WSGI` environment is used wholesale as a traversal path. In a hybrid + application, the traversal path is not the entire ``PATH_INFO`` string, but a + portion of the URL determined by a matching pattern in the matched route + configuration's pattern. -- In a purely traversal based application, view configurations which - do not mention a ``route_name`` argument are considered during - :term:`view lookup`; in a hybrid application, when a route is - matched, only view configurations which mention that route's name as - a ``route_name`` are considered during :term:`view lookup`. +- In a purely traversal-based application, view configurations which do not + mention a ``route_name`` argument are considered during :term:`view lookup`. + In a hybrid application, when a route is matched, only view configurations + which mention that route's name as a ``route_name`` are considered during + :term:`view lookup`. -More generally, a hybrid application *is* a traversal-based -application except: +More generally, a hybrid application *is* a traversal-based application except: -- the traversal *root* is chosen based on the route configuration of - the route that matched instead of from the ``root_factory`` supplied - during application startup configuration. +- the traversal *root* is chosen based on the route configuration of the route + that matched, instead of from the ``root_factory`` supplied during + application startup configuration. -- the traversal *path* is chosen based on the route configuration of - the route that matched rather than from the ``PATH_INFO`` of a - request. +- the traversal *path* is chosen based on the route configuration of the route + that matched, rather than from the ``PATH_INFO`` of a request. -- the set of views that may be chosen during :term:`view lookup` when - a route matches are limited to those which specifically name a - ``route_name`` in their configuration that is the same as the - matched route's ``name``. +- the set of views that may be chosen during :term:`view lookup` when a route + matches are limited to those which specifically name a ``route_name`` in + their configuration that is the same as the matched route's ``name``. -To create a hybrid mode application, use a :term:`route configuration` -that implies a particular :term:`root factory` and which also includes -a ``pattern`` argument that contains a special dynamic part: either -``*traverse`` or ``*subpath``. +To create a hybrid mode application, use a :term:`route configuration` that +implies a particular :term:`root factory` and which also includes a ``pattern`` +argument that contains a special dynamic part: either ``*traverse`` or +``*subpath``. The Root Object for a Route Match ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A hybrid application implies that traversal is performed during a -request after a route has matched. Traversal, by definition, must -always begin at a root object. Therefore it's important to know -*which* root object will be traversed after a route has matched. +A hybrid application implies that traversal is performed during a request after +a route has matched. Traversal, by definition, must always begin at a root +object. Therefore it's important to know *which* root object will be traversed +after a route has matched. -Figuring out which :term:`root` object results from a particular route -match is straightforward. When a route is matched: +Figuring out which :term:`root` object results from a particular route match is +straightforward. When a route is matched: -- If the route's configuration has a ``factory`` argument which - points to a :term:`root factory` callable, that callable will be - called to generate a :term:`root` object. +- If the route's configuration has a ``factory`` argument which points to a + :term:`root factory` callable, that callable will be called to generate a + :term:`root` object. -- If the route's configuration does not have a ``factory`` - argument, the *global* :term:`root factory` will be called to - generate a :term:`root` object. The global root factory is the - callable implied by the ``root_factory`` argument passed to the - :class:`~pyramid.config.Configurator` at application - startup time. +- If the route's configuration does not have a ``factory`` argument, the + *global* :term:`root factory` will be called to generate a :term:`root` + object. The global root factory is the callable implied by the + ``root_factory`` argument passed to the :class:`~pyramid.config.Configurator` + at application startup time. - If a ``root_factory`` argument is not provided to the - :class:`~pyramid.config.Configurator` at startup time, a - *default* root factory is used. The default root factory is used to - generate a root object. + :class:`~pyramid.config.Configurator` at startup time, a *default* root + factory is used. The default root factory is used to generate a root object. .. note:: Root factories related to a route were explained previously within - :ref:`route_factories`. Both the global root factory and default - root factory were explained previously within - :ref:`the_resource_tree`. + :ref:`route_factories`. Both the global root factory and default root + factory were explained previously within :ref:`the_resource_tree`. .. index:: pair: hybrid applications; *traverse route pattern .. _using_traverse_in_a_route_pattern: -Using ``*traverse`` In a Route Pattern +Using ``*traverse`` in a Route Pattern ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A hybrid application most often implies the inclusion of a route -configuration that contains the special token ``*traverse`` at the end -of a route's pattern: +A hybrid application most often implies the inclusion of a route configuration +that contains the special token ``*traverse`` at the end of a route's pattern: .. code-block:: python :linenos: config.add_route('home', '{foo}/{bar}/*traverse') -A ``*traverse`` token at the end of the pattern in a route's -configuration implies a "remainder" *capture* value. When it is used, -it will match the remainder of the path segments of the URL. This -remainder becomes the path used to perform traversal. +A ``*traverse`` token at the end of the pattern in a route's configuration +implies a "remainder" *capture* value. When it is used, it will match the +remainder of the path segments of the URL. This remainder becomes the path +used to perform traversal. .. note:: - The ``*remainder`` route pattern syntax is explained in more - detail within :ref:`route_pattern_syntax`. + The ``*remainder`` route pattern syntax is explained in more detail within + :ref:`route_pattern_syntax`. A hybrid mode application relies more heavily on :term:`traversal` to do :term:`resource location` and :term:`view lookup` than most examples indicate within :ref:`urldispatch_chapter`. -Because the pattern of the above route ends with ``*traverse``, when this -route configuration is matched during a request, :app:`Pyramid` will attempt -to use :term:`traversal` against the :term:`root` object implied by the -:term:`root factory` that is implied by the route's configuration. Since no +Because the pattern of the above route ends with ``*traverse``, when this route +configuration is matched during a request, :app:`Pyramid` will attempt to use +:term:`traversal` against the :term:`root` object implied by the :term:`root +factory` that is implied by the route's configuration. Since no ``root_factory`` argument is explicitly specified for this route, this will -either be the *global* root factory for the application, or the *default* -root factory. Once :term:`traversal` has found a :term:`context` resource, +either be the *global* root factory for the application, or the *default* root +factory. Once :term:`traversal` has found a :term:`context` resource, :term:`view lookup` will be invoked in almost exactly the same way it would have been invoked in a "pure" traversal-based application. -Let's assume there is no *global* :term:`root factory` configured in -this application. The *default* :term:`root factory` cannot be traversed: -it has no useful ``__getitem__`` method. So we'll need to associate -this route configuration with a custom root factory in order to -create a useful hybrid application. To that end, let's imagine that -we've created a root factory that looks like so in a module named -``routes.py``: +Let's assume there is no *global* :term:`root factory` configured in this +application. The *default* :term:`root factory` cannot be traversed; it has no +useful ``__getitem__`` method. So we'll need to associate this route +configuration with a custom root factory in order to create a useful hybrid +application. To that end, let's imagine that we've created a root factory that +looks like so in a module named ``routes.py``: .. code-block:: python :linenos: @@ -246,7 +233,7 @@ we've created a root factory that looks like so in a module named def root_factory(request): return root -Above, we've defined a (bogus) resource tree that can be traversed, and a +Above we've defined a (bogus) resource tree that can be traversed, and a ``root_factory`` function that can be used as part of a particular route configuration statement: @@ -256,8 +243,8 @@ configuration statement: config.add_route('home', '{foo}/{bar}/*traverse', factory='mypackage.routes.root_factory') -The ``factory`` above points at the function we've defined. It will return -an instance of the ``Resource`` class as a root object whenever this route is +The ``factory`` above points at the function we've defined. It will return an +instance of the ``Resource`` class as a root object whenever this route is matched. Instances of the ``Resource`` class can be used for tree traversal because they have a ``__getitem__`` method that does something nominally useful. Since traversal uses ``__getitem__`` to walk the resources of a @@ -266,39 +253,37 @@ statement is a reasonable thing to do. .. note:: - We could have also used our ``root_factory`` function as the - ``root_factory`` argument of the - :class:`~pyramid.config.Configurator` constructor, instead - of associating it with a particular route inside the route's - configuration. Every hybrid route configuration that is matched but - which does *not* name a ``factory`` attribute will use the use - global ``root_factory`` function to generate a root object. + We could have also used our ``root_factory`` function as the ``root_factory`` + argument of the :class:`~pyramid.config.Configurator` constructor, instead of + associating it with a particular route inside the route's configuration. + Every hybrid route configuration that is matched, but which does *not* name a + ``factory`` attribute, will use the global ``root_factory`` function to + generate a root object. -When the route configuration named ``home`` above is matched during a -request, the matchdict generated will be based on its pattern: +When the route configuration named ``home`` above is matched during a request, +the matchdict generated will be based on its pattern: ``{foo}/{bar}/*traverse``. The "capture value" implied by the ``*traverse`` element in the pattern will be used to traverse the resource tree in order to find a context resource, starting from the root object returned from the root factory. In the above example, the :term:`root` object found will be the instance named ``root`` in ``routes.py``. -If the URL that matched a route with the pattern ``{foo}/{bar}/*traverse``, -is ``http://example.com/one/two/a/b/c``, the traversal path used -against the root object will be ``a/b/c``. As a result, -:app:`Pyramid` will attempt to traverse through the edges ``'a'``, -``'b'``, and ``'c'``, beginning at the root object. +If the URL that matched a route with the pattern ``{foo}/{bar}/*traverse`` is +``http://example.com/one/two/a/b/c``, the traversal path used against the root +object will be ``a/b/c``. As a result, :app:`Pyramid` will attempt to traverse +through the edges ``'a'``, ``'b'``, and ``'c'``, beginning at the root object. -In our above example, this particular set of traversal steps will mean that -the :term:`context` resource of the view would be the ``Resource`` object -we've named ``'c'`` in our bogus resource tree and the :term:`view name` -resulting from traversal will be the empty string; if you need a refresher -about why this outcome is presumed, see :ref:`traversal_algorithm`. +In our above example, this particular set of traversal steps will mean that the +:term:`context` resource of the view would be the ``Resource`` object we've +named ``'c'`` in our bogus resource tree, and the :term:`view name` resulting +from traversal will be the empty string. If you need a refresher about why +this outcome is presumed, see :ref:`traversal_algorithm`. -At this point, a suitable view callable will be found and invoked -using :term:`view lookup` as described in :ref:`view_configuration`, -but with a caveat: in order for view lookup to work, we need to define -a view configuration that will match when :term:`view lookup` is -invoked after a route matches: +At this point, a suitable view callable will be found and invoked using +:term:`view lookup` as described in :ref:`view_configuration`, but with a +caveat: in order for view lookup to work, we need to define a view +configuration that will match when :term:`view lookup` is invoked after a route +matches: .. code-block:: python :linenos: @@ -307,28 +292,28 @@ invoked after a route matches: factory='mypackage.routes.root_factory') config.add_view('mypackage.views.myview', route_name='home') -Note that the above call to -:meth:`~pyramid.config.Configurator.add_view` includes a ``route_name`` -argument. View configurations that include a ``route_name`` argument are -meant to associate a particular view declaration with a route, using the -route's name, in order to indicate that the view should *only be invoked when -the route matches*. +Note that the above call to :meth:`~pyramid.config.Configurator.add_view` +includes a ``route_name`` argument. View configurations that include a +``route_name`` argument are meant to associate a particular view declaration +with a route, using the route's name, in order to indicate that the view should +*only be invoked when the route matches*. Calls to :meth:`~pyramid.config.Configurator.add_view` may pass a ``route_name`` attribute, which refers to the value of an existing route's -``name`` argument. In the above example, the route name is ``home``, -referring to the name of the route defined above it. +``name`` argument. In the above example, the route name is ``home``, referring +to the name of the route defined above it. -The above ``mypackage.views.myview`` view callable will be invoked when: +The above ``mypackage.views.myview`` view callable will be invoked when the +following conditions are met: -- the route named "home" is matched +- The route named "home" is matched. -- the :term:`view name` resulting from traversal is the empty string. +- The :term:`view name` resulting from traversal is the empty string. -- the :term:`context` resource is any object. +- The :term:`context` resource is any object. -It is also possible to declare alternate views that may be invoked -when a hybrid route is matched: +It is also possible to declare alternative views that may be invoked when a +hybrid route is matched: .. code-block:: python :linenos: @@ -340,37 +325,37 @@ when a hybrid route is matched: name='another') The ``add_view`` call for ``mypackage.views.another_view`` above names a -different view and, more importantly, a different :term:`view name`. The -above ``mypackage.views.another_view`` view will be invoked when: +different view and, more importantly, a different :term:`view name`. The above +``mypackage.views.another_view`` view will be invoked when the following +conditions are met: -- the route named "home" is matched +- The route named "home" is matched. -- the :term:`view name` resulting from traversal is ``another``. +- The :term:`view name` resulting from traversal is ``another``. -- the :term:`context` resource is any object. +- The :term:`context` resource is any object. For instance, if the URL ``http://example.com/one/two/a/another`` is provided to an application that uses the previously mentioned resource tree, the -``mypackage.views.another`` view callable will be called instead of the -``mypackage.views.myview`` view callable because the :term:`view name` will -be ``another`` instead of the empty string. +``mypackage.views.another_view`` view callable will be called instead of the +``mypackage.views.myview`` view callable because the :term:`view name` will be +``another`` instead of the empty string. More complicated matching can be composed. All arguments to *route* -configuration statements and *view* configuration statements are -supported in hybrid applications (such as :term:`predicate` -arguments). +configuration statements and *view* configuration statements are supported in +hybrid applications (such as :term:`predicate` arguments). -Using the ``traverse`` Argument In a Route Definition +Using the ``traverse`` Argument in a Route Definition ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Rather than using the ``*traverse`` remainder marker in a pattern, you -can use the ``traverse`` argument to the -:meth:`~pyramid.config.Configurator.add_route` method. +Rather than using the ``*traverse`` remainder marker in a pattern, you can use +the ``traverse`` argument to the :meth:`~pyramid.config.Configurator.add_route` +method. -When you use the ``*traverse`` remainder marker, the traversal path is -limited to being the remainder segments of a request URL when a route -matches. However, when you use the ``traverse`` argument or -attribute, you have more control over how to compose a traversal path. +When you use the ``*traverse`` remainder marker, the traversal path is limited +to being the remainder segments of a request URL when a route matches. +However, when you use the ``traverse`` argument or attribute, you have more +control over how to compose a traversal path. Here's a use of the ``traverse`` pattern in a call to :meth:`~pyramid.config.Configurator.add_route`: @@ -381,30 +366,27 @@ Here's a use of the ``traverse`` pattern in a call to config.add_route('abc', '/articles/{article}/edit', traverse='/{article}') -The syntax of the ``traverse`` argument is the same as it is for -``pattern``. +The syntax of the ``traverse`` argument is the same as it is for ``pattern``. -If, as above, the ``pattern`` provided is ``/articles/{article}/edit``, -and the ``traverse`` argument provided is ``/{article}``, when a -request comes in that causes the route to match in such a way that the -``article`` match value is ``1`` (when the request URI is -``/articles/1/edit``), the traversal path will be generated as ``/1``. -This means that the root object's ``__getitem__`` will be called with -the name ``1`` during the traversal phase. If the ``1`` object -exists, it will become the :term:`context` of the request. -The :ref:`traversal_chapter` chapter has more information about traversal. +If, as above, the ``pattern`` provided is ``/articles/{article}/edit``, and the +``traverse`` argument provided is ``/{article}``, when a request comes in that +causes the route to match in such a way that the ``article`` match value is +``1`` (when the request URI is ``/articles/1/edit``), the traversal path will +be generated as ``/1``. This means that the root object's ``__getitem__`` will +be called with the name ``1`` during the traversal phase. If the ``1`` object +exists, it will become the :term:`context` of the request. The +:ref:`traversal_chapter` chapter has more information about traversal. -If the traversal path contains segment marker names which are not -present in the pattern argument, a runtime error will occur. The -``traverse`` pattern should not contain segment markers that do not -exist in the ``path``. +If the traversal path contains segment marker names which are not present in +the pattern argument, a runtime error will occur. The ``traverse`` pattern +should not contain segment markers that do not exist in the ``path``. -Note that the ``traverse`` argument is ignored when attached to a -route that has a ``*traverse`` remainder marker in its pattern. +Note that the ``traverse`` argument is ignored when attached to a route that +has a ``*traverse`` remainder marker in its pattern. -Traversal will begin at the root object implied by this route (either -the global root, or the object returned by the ``factory`` associated -with this route). +Traversal will begin at the root object implied by this route (either the +global root, or the object returned by the ``factory`` associated with this +route). .. index:: pair: hybrid applications; global views @@ -412,14 +394,13 @@ with this route). Making Global Views Match +++++++++++++++++++++++++ -By default, only view configurations that mention a ``route_name`` -will be found during view lookup when a route that has a ``*traverse`` -in its pattern matches. You can allow views without a ``route_name`` -attribute to match a route by adding the ``use_global_views`` flag to -the route definition. For example, the ``myproject.views.bazbuz`` -view below will be found if the route named ``abc`` below is matched -and the ``PATH_INFO`` is ``/abc/bazbuz``, even though the view -configuration statement does not have the ``route_name="abc"`` +By default, only view configurations that mention a ``route_name`` will be +found during view lookup when a route that has a ``*traverse`` in its pattern +matches. You can allow views without a ``route_name`` attribute to match a +route by adding the ``use_global_views`` flag to the route definition. For +example, the ``myproject.views.bazbuz`` view below will be found if the route +named ``abc`` below is matched and the ``PATH_INFO`` is ``/abc/bazbuz``, even +though the view configuration statement does not have the ``route_name="abc"`` attribute. .. code-block:: python @@ -445,10 +426,10 @@ traversal. For instance, the :func:`pyramid.wsgi.wsgiapp2` decorator and the from the request's subpath when its ``use_subpath`` argument is ``True``, so it's useful to be able to influence this value. -When ``*subpath`` exists in a pattern, no path is actually traversed, -but the traversal algorithm will return a :term:`subpath` list implied -by the capture value of ``*subpath``. You'll see this pattern most -commonly in route declarations that look like this: +When ``*subpath`` exists in a pattern, no path is actually traversed, but the +traversal algorithm will return a :term:`subpath` list implied by the capture +value of ``*subpath``. You'll see this pattern most commonly in route +declarations that look like this: .. code-block:: python :linenos: @@ -460,98 +441,13 @@ commonly in route declarations that look like this: config.add_route('static', '/static/*subpath') config.add_view(www, route_name='static') -``mypackage.views.www`` is an instance of -:class:`pyramid.static.static_view`. This effectively tells the static -helper to traverse everything in the subpath as a filename. - -.. index:: - pair: hybrid applications; corner cases - -Corner Cases ------------- - -A number of corner case "gotchas" exist when using a hybrid -application. We'll detail them here. - -Registering a Default View for a Route That Has a ``view`` Attribute -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. warning:: As of :app:`Pyramid` 1.1 this section is slated to be removed in - a later documentation release because the ability to add views - directly to the :term:`route configuration` by passing a ``view`` argument - to ``add_route`` has been deprecated. - -It is an error to provide *both* a ``view`` argument to a :term:`route -configuration` *and* a :term:`view configuration` which names a -``route_name`` that has no ``name`` value or the empty ``name`` value. For -example, this pair of declarations will generate a conflict error at startup -time. - -.. code-block:: python - :linenos: - - config.add_route('home', '{foo}/{bar}/*traverse', - view='myproject.views.home') - config.add_view('myproject.views.another', route_name='home') - -This is because the ``view`` argument to the -:meth:`~pyramid.config.Configurator.add_route` above is an *implicit* -default view when that route matches. ``add_route`` calls don't *need* to -supply a view attribute. For example, this ``add_route`` call: - -.. code-block:: python - :linenos: - - config.add_route('home', '{foo}/{bar}/*traverse', - view='myproject.views.home') +``mypackage.views.www`` is an instance of :class:`pyramid.static.static_view`. +This effectively tells the static helper to traverse everything in the subpath +as a filename. -Can also be spelled like so: - -.. code-block:: python - :linenos: - - config.add_route('home', '{foo}/{bar}/*traverse') - config.add_view('myproject.views.home', route_name='home') - -The two spellings are logically equivalent. In fact, the former is just a -syntactical shortcut for the latter. - -Binding Extra Views Against a Route Configuration that Doesn't Have a ``*traverse`` Element In Its Pattern -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Here's another corner case that just makes no sense: - -.. code-block:: python - :linenos: - - config.add_route('abc', '/abc', view='myproject.views.abc') - config.add_view('myproject.views.bazbuz', name='bazbuz', - route_name='abc') - -The above view declaration is useless, because it will never be matched when -the route it references has matched. Only the view associated with the route -itself (``myproject.views.abc``) will ever be invoked when the route matches, -because the default view is always invoked when a route matches and when no -post-match traversal is performed. - -To make the above view declaration useful, the special ``*traverse`` -token must end the route's pattern. For example: - -.. code-block:: python - :linenos: - - config.add_route('abc', '/abc/*traverse', view='myproject.views.abc') - config.add_view('myproject.views.bazbuz', name='bazbuz', - route_name='abc') - -With the above configuration, the ``myproject.views.bazbuz`` view will -be invoked when the request URI is ``/abc/bazbuz``, assuming there is -no object contained by the root object with the key ``bazbuz``. A -different request URI, such as ``/abc/foo/bar``, would invoke the -default ``myproject.views.abc`` view. .. index:: - pair: hybrid urls; generating + pair: hybrid URLs; generating .. _generating_hybrid_urls: @@ -560,16 +456,16 @@ Generating Hybrid URLs .. versionadded:: 1.5 -The :meth:`pyramid.request.Request.resource_url` method and the -:meth:`pyramid.request.Request.resource_path` method both accept optional +The :meth:`pyramid.request.Request.resource_url` method and the +:meth:`pyramid.request.Request.resource_path` method both accept optional keyword arguments that make it easier to generate route-prefixed URLs that -contain paths to traversal resources:``route_name``, ``route_kw``, and +contain paths to traversal resources: ``route_name``, ``route_kw``, and ``route_remainder_name``. Any route that has a pattern that contains a ``*remainder`` pattern (any -stararg remainder pattern, such as ``*traverse`` or ``*subpath`` or ``*fred``) -can be used as the target name for ``request.resource_url(..., route_name=)`` -and ``request.resource_path(..., route_name=)``. +stararg remainder pattern, such as ``*traverse``, ``*subpath``, or ``*fred``) +can be used as the target name for ``request.resource_url(..., route_name=)`` +and ``request.resource_path(..., route_name=)``. For example, let's imagine you have a route defined in your Pyramid application like so: @@ -578,7 +474,7 @@ like so: config.add_route('mysection', '/mysection*traverse') -If you'd like to generate the URL ``http://example.com/mysection/a/``, you can +If you'd like to generate the URL ``http://example.com/mysection/a/``, you can use the following incantation, assuming that the variable ``a`` below points to a resource that is a child of the root with a ``__name__`` of ``a``: @@ -592,14 +488,14 @@ You can generate only the path portion ``/mysection/a/`` assuming the same: request.resource_path(a, route_name='mysection') -The path is virtual host aware, so if the ``X-Vhm-Root`` environ variable is -present in the request, and it's set to ``/a``, the above call to -``request.resource_url`` would generate ``http://example.com/mysection/`` -and the above call to ``request.resource_path`` would generate ``/mysection/``. -See :ref:`virtual_root_support` for more information. +The path is virtual host aware, so if the ``X-Vhm-Root`` environment variable +is present in the request, and it's set to ``/a``, the above call to +``request.resource_url`` would generate ``http://example.com/mysection/``, and +the above call to ``request.resource_path`` would generate ``/mysection/``. See +:ref:`virtual_root_support` for more information. If the route you're trying to use needs simple dynamic part values to be filled -in to succesfully generate the URL, you can pass these as the ``route_kw`` +in to succesfully generate the URL, you can pass these as the ``route_kw`` argument to ``resource_url`` and ``resource_path``. For example, assuming that the route definition is like so: @@ -613,15 +509,15 @@ You can pass ``route_kw`` in to fill in ``{id}`` above: request.resource_url(a, route_name='mysection', route_kw={'id':'1'}) -If you pass ``route_kw`` but do not pass ``route_name``, ``route_kw`` will -be ignored. +If you pass ``route_kw`` but do not pass ``route_name``, ``route_kw`` will be +ignored. -By default this feature works by calling ``route_url`` under the hood, -and passing the value of the resource path to that function as ``traverse``. -If your route has a different ``*stararg`` remainder name (such as -``*subpath``), you can tell ``resource_url`` or ``resource_path`` to use that -instead of ``traverse`` by passing ``route_remainder_name``. For example, -if you have the following route: +By default this feature works by calling ``route_url`` under the hood, and +passing the value of the resource path to that function as ``traverse``. If +your route has a different ``*stararg`` remainder name (such as ``*subpath``), +you can tell ``resource_url`` or ``resource_path`` to use that instead of +``traverse`` by passing ``route_remainder_name``. For example, if you have the +following route: .. code-block:: python @@ -631,10 +527,10 @@ You can fill in the ``*subpath`` value using ``resource_url`` by doing: .. code-block:: python - request.resource_path(a, route_name='mysection', + request.resource_path(a, route_name='mysection', route_remainder_name='subpath') -If you pass ``route_remainder_name`` but do not pass ``route_name``, +If you pass ``route_remainder_name`` but do not pass ``route_name``, ``route_remainder_name`` will be ignored. If you try to use ``resource_path`` or ``resource_url`` when the ``route_name`` @@ -642,12 +538,11 @@ argument points at a route that does not have a remainder stararg, an error will not be raised, but the generated URL will not contain any remainder information either. -All other values that are normally passable to ``resource_path`` and -``resource_url`` (such as ``query``, ``anchor``, ``host``, ``port``, and +All other values that are normally passable to ``resource_path`` and +``resource_url`` (such as ``query``, ``anchor``, ``host``, ``port``, and positional elements) work as you might expect in this configuration. Note that this feature is incompatible with the ``__resource_url__`` feature (see :ref:`overriding_resource_url_generation`) implemented on resource objects. Any ``__resource_url__`` supplied by your resource will be ignored when you pass ``route_name``. - |
