diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/narr/configuration.rst | 9 | ||||
| -rw-r--r-- | docs/narr/contextfinding.rst | 13 | ||||
| -rw-r--r-- | docs/narr/firstapp.rst | 10 | ||||
| -rw-r--r-- | docs/narr/handlers.rst | 46 | ||||
| -rw-r--r-- | docs/narr/hybrid.rst | 72 | ||||
| -rw-r--r-- | docs/narr/install.rst | 1 | ||||
| -rw-r--r-- | docs/narr/project.rst | 13 | ||||
| -rw-r--r-- | docs/narr/static.rst | 76 | ||||
| -rw-r--r-- | docs/narr/traversal.rst | 2 | ||||
| -rw-r--r-- | docs/narr/urldispatch.rst | 84 | ||||
| -rw-r--r-- | docs/narr/views.rst | 406 | ||||
| -rw-r--r-- | docs/narr/webob.rst | 21 |
12 files changed, 421 insertions, 332 deletions
diff --git a/docs/narr/configuration.rst b/docs/narr/configuration.rst index 28388ef96..4f26b092a 100644 --- a/docs/narr/configuration.rst +++ b/docs/narr/configuration.rst @@ -10,9 +10,9 @@ Each deployment of an application written using :app:`Pyramid` implies a specific *configuration* of the framework itself. For example, an application which serves up MP3s for user consumption might plug code into the framework that manages songs, while an application that manages corporate -data might plug in code that manages accounting information. :app:`Pyramid` -refers to the way in which code is plugged in to it for a specific -application as "configuration". +data might plug in code that manages accounting information. The way in which +code is plugged in to :app:`Pyramid`, for a specific application, is referred +to as "configuration". Most people understand "configuration" as coarse settings that inform the high-level operation of a specific application deployment. For instance, @@ -21,8 +21,7 @@ application startup time as "configuration". :app:`Pyramid` extends this pattern to application development, using the term "configuration" to express standardized ways that code gets plugged into a deployment of the framework itself. When you plug code into the :app:`Pyramid` framework, you are -"configuring" :app:`Pyramid` for the purpose of creating a particular -application deployment. +"configuring" :app:`Pyramid` to create a particular application. .. index:: single: imperative configuration diff --git a/docs/narr/contextfinding.rst b/docs/narr/contextfinding.rst index 770f97d15..691ad7b8e 100644 --- a/docs/narr/contextfinding.rst +++ b/docs/narr/contextfinding.rst @@ -51,16 +51,15 @@ requesting user. that do not provide a notion of a context. There are two separate :term:`context finding` subsystems in -:app:`Pyramid`: :term:`traversal` and :term:`URL dispatch`. The -subsystems are documented within this chapter. They can be used -separately or they can be combined. Three chapters which follow -describe :term:`context finding`: :ref:`traversal_chapter`, +:app:`Pyramid`: :term:`traversal` and :term:`URL dispatch`. They can +be used separately or they can be combined. Three chapters which +follow describe :term:`context finding`: :ref:`traversal_chapter`, :ref:`urldispatch_chapter` and :ref:`hybrid_chapter`. There is only one :term:`view lookup` subsystem present in -:app:`Pyramid`. Where appropriate, within this chapter, we -describe how view lookup interacts with context finding. One chapter -which follows describes :term:`view lookup`: :ref:`views_chapter`. +: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 Context Finding? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/narr/firstapp.rst b/docs/narr/firstapp.rst index d23a79c4b..b40faee3d 100644 --- a/docs/narr/firstapp.rst +++ b/docs/narr/firstapp.rst @@ -137,10 +137,10 @@ passed to the ``Response`` constructor as the *body* of the response. In the Application Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~ -In the above script, the following code, representing the -*configuration* of an application which uses the previously defined -imports and function definitions is placed within the confines of an -``if`` statement: +In the above script, the following code represents the *configuration* of this +simple application. The application is configured using the previously defined +imports and function definitions, placed within the confines of an ``if`` +statement: .. code-block:: python :linenos: @@ -242,7 +242,7 @@ circumstances which would cause the view configuration's callable to be invoked. In general, a greater number of predicates supplied along with a view configuration will more strictly limit the applicability of its associated view callable. When :app:`Pyramid` processes a -request, however, the view callable with the *most specific* view +request, the view callable with the *most specific* view configuration (the view configuration that matches the most specific set of predicates) is always invoked. diff --git a/docs/narr/handlers.rst b/docs/narr/handlers.rst index 9a5267b2a..f6e658cf0 100644 --- a/docs/narr/handlers.rst +++ b/docs/narr/handlers.rst @@ -19,20 +19,21 @@ predicate` to control which method of the handler is called. :term:`url dispatch`. The concept of a view handler is analogous to a "controller" in Pylons 1.0. -The view handler class is initialized by :app:`Pyramid` in the same manner as -a view class. Its ``__init__`` is called with a request object (see -:ref:`class_as_view`) when a request enters the system which corresponds with -a view handler registration made during configuration. A method of the view -handler class is then called. The method which is called depends on the view -handler configuration. - -The :meth:`pyramid.config.Configurator.add_handler` method will scan -the handler class and automatically set up views for methods that are -auto-exposed or were decorated with :class:`~pyramid.view.action`. The -:class:`~pyramid.view.action` decorator is used to setup additional view -configuration information for individual class methods, and can be used -repeatedly for a single method to register multiple view configurations that -will call that view callable. +The view handler class is initialized by :app:`Pyramid` in the same +manner as a view class. Its ``__init__`` is called with a request +object (see :ref:`class_as_view`) as its argument when a request enters +the system which corresponds with a view handler registration made +during configuration. After the view handler class is instantiated, a +method on the instance is called. The method which is called depends on +the view handler configuration. + +The :meth:`pyramid.config.Configurator.add_handler` method will +scan the handler class and automatically set up views for methods that +are auto-exposed, or were decorated with the +:class:`~pyramid.view.action` decorator. This decorator is used to setup +additional view configuration information for individual methods of the +class, and can be used repeatedly for a single view method to +register multiple view configurations for it. Here's an example view handler class: @@ -82,9 +83,9 @@ specific ``action`` name: handler=Hello, action='index') This will result one of the methods that are configured for the ``action`` of -'index' in the ``Hello`` handler class to be called. Other methods in the -handler class not named 'index' might be called if they were configured to be -called when the ``action`` name is 'index' as will be seen below. +'index' in the ``Hello`` handler class to be called. In this case the name +of the method is the same as the action name: 'index'. However, this +need not be the case, as we will see below. .. note:: @@ -175,7 +176,7 @@ Action Decorator ---------------- The :class:`~pyramid.view.action` decorator registers view configuration -information on the handler method which is used by +information on the handler method, which is used by :meth:`~pyramid.config.Configurator.add_handler` to setup the view configuration. @@ -210,10 +211,11 @@ Example: This will register two views that require the ``action`` to be ``index``, with the additional view predicate requiring a specific request method. -When a method is decorated multiple times with :class:`~pyramid.view.action`, -a view configuration will be registered for each call, with the view callable -being the method decorated. Used with a combination of ``name``, multiple -URL's can result in different template renderings with the same data. +It can be useful to decorate a single method multiple times with +:class:`~pyramid.view.action`. Each action decorator will register a new view +for the method. By specifying different names and renderers for each action, +the same view logic can be exposed and rendered differently on multiple +URLs. Example: diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst index b599fefdd..da77a28f0 100644 --- a/docs/narr/hybrid.rst +++ b/docs/narr/hybrid.rst @@ -102,7 +102,7 @@ application and a hybrid application: 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 + 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. @@ -207,16 +207,20 @@ the matched route's configuration. 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` implied by the route's -configuration. Once :term:`traversal` has found a :term:`context`, +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`, :term:`view lookup` will be invoked in almost exactly the same way it would have been invoked in a "pure" traversal-based 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 non-default 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 +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 @@ -236,7 +240,7 @@ created a root factory that looks like so in a module named def root_factory(request): return root -Above, we've defined a (bogus) graph here that can be traversed, and a +Above, we've defined a (bogus) graph that can be traversed, and a ``root_factory`` function that can be used as part of a particular route configuration statement: @@ -246,20 +250,20 @@ route 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 ``Traversable`` class as a root object -whenever this route is matched. Because the ``Traversable`` object -we've defined has a ``__getitem__`` method that does something -nominally useful, and because traversal uses ``__getitem__`` to walk -the nodes that make up an object graph, using traversal against the -root object implied by our route statement becomes a reasonable thing -to do. +The ``factory`` above points at the function we've defined. It will +return an instance of the ``Traversable`` class as a root object +whenever this route is matched. Instances of the``Traversable`` class +can be used for graph traversal because they have a ``__getitem__`` +method that does something nominally useful. Since traversal uses +``__getitem__`` to walk the nodes of an object graph, using traversal +against the root object implied by our route statement is a reasonable +thing to do. .. note:: We could have also used our ``root_factory`` callable as the ``root_factory`` argument of the - :class:`pyramid.config.Configurator` constructor instead + :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 @@ -308,7 +312,7 @@ 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 +``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. @@ -385,7 +389,7 @@ request comes in that causes the route to match in such a way that the 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. -:ref:`traversal_chapter` has more information about traversal. +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 @@ -402,14 +406,15 @@ with this route). Making Global Views Match +++++++++++++++++++++++++ -By default, view configurations that don't mention a ``route_name`` will be -not found by view lookup when a route that mentions a ``*traverse`` in its -pattern matches. You can make these match forcibly 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. +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 :linenos: @@ -493,10 +498,10 @@ Can also be spelled like so: 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 Patttern +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. +Here's another corner case that just makes no sense: .. code-block:: python :linenos: @@ -511,7 +516,7 @@ 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 non-useless, the special ``*traverse`` +To make the above view declaration useful, the special ``*traverse`` token must end the route's pattern. For example: .. code-block:: python @@ -521,3 +526,8 @@ token must end the route's pattern. For example: 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. diff --git a/docs/narr/install.rst b/docs/narr/install.rst index db1cfaf9d..abc4f539c 100644 --- a/docs/narr/install.rst +++ b/docs/narr/install.rst @@ -86,7 +86,6 @@ the following commands: [chrism@vitaminf ~]$ mkdir tmp [chrism@vitaminf ~]$ mkdir opt [chrism@vitaminf ~]$ cd tmp - [chrism@vitaminf tmp]$ cd tmp [chrism@vitaminf tmp]$ wget \ http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tgz [chrism@vitaminf tmp]$ tar xvzf Python-2.6.4.tgz diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 6cfd31c0b..f8a9017db 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -145,6 +145,17 @@ project we name ``MyProject``: name during ``paster create`` by adding the project name to the command line, e.g. ``paster create -t pyramid_starter MyProject``. +.. note:: You may encounter an error when using ``paster create`` + if a dependent Python package is not installed. This will + result in a traceback ending in: + + .. code-block:: text + + pkg_resources.DistributionNotFound: <package name> + + Simply run ``bin/easy_install``, with the missing package + name from the error message, to workaround this issue. + As a result of invoking the ``paster create`` command, a project is created in a directory named ``MyProject``. That directory is a :term:`setuptools` :term:`project` directory from which a setuptools @@ -760,7 +771,7 @@ also informs Python that the directory which contains it is a *package*. :term:`context` of the request is an instance of the :class:`myproject.models.MyModel` class. The first argument to ``add_view`` points at a Python function that does all the work for this - view, also known as a :term:`view callable` via a :term:`dotted Python + view, also known as a :term:`view callable`, via a :term:`dotted Python name`. The view declaration also names a ``renderer``, which in this case is a template that will be used to render the result of the view callable. This particular view declaration points at diff --git a/docs/narr/static.rst b/docs/narr/static.rst index 9547e73fc..172fb08d4 100644 --- a/docs/narr/static.rst +++ b/docs/narr/static.rst @@ -1,8 +1,8 @@ Static Resources ================ -:app:`Pyramid` makes it possible to serve up "static" (non-dynamic) -resources from a directory on a filesystem. This chapter describes +:app:`Pyramid` makes it possible to serve up static +resources files from a directory on a filesystem. This chapter describes how to configure :app:`Pyramid` to do so. .. index:: @@ -20,7 +20,7 @@ application root URL, e.g. ``/static``. Note that the ``path`` provided to :meth:`pyramid.config.Configurator.add_static_view` may be a fully -qualified :term:`resource specification` or an *absolute path*. +qualified :term:`resource specification`, or an *absolute path*. Here's an example of a use of :meth:`pyramid.config.Configurator.add_static_view` that will serve @@ -100,7 +100,7 @@ provided with a ``name`` argument that is the URL prefix ``http://example.com/images``, subsequent calls to :func:`pyramid.url.static_url` with paths that start with the ``path`` argument passed to :meth:`pyramid.config.Configurator.add_static_view` -will generate a URL something like ``http://example.com/logo.png``. The +will generate a URL something like ``http://example.com/images/logo.png``. The external webserver listening on ``example.com`` must be itself configured to respond properly to such a request. The :func:`pyramid.url.static_url` API is discussed in more detail later in this chapter. @@ -110,6 +110,25 @@ to :meth:`pyramid.config.Configurator.add_static_view`. Use of the :ref:`static_directive` ZCML directive is completely equivalent to using imperative configuration for the same purpose. +.. note:: + + Using :func:`pyramid.url.static_url` in conjunction with a + :meth:`pyramid.configuration.Configurator.add_static_view` makes it + possible to put static media on a separate webserver during production (if + the ``name`` argument to + :meth:`pyramid.configuration.Configurator.add_static_view` is a URL), + while keeping static media package-internal and served by the development + webserver during development (if the ``name`` argument to + :meth:`pyramid.configuration.Configurator.add_static_view` is a view + name). To create such a circumstance, we suggest using the + :attr:`pyramid.registry.Registry.settings` API in conjunction with a + setting in the application ``.ini`` file named ``media_location``. Then + set the value of ``media_location`` to either a view name or a URL + depending on whether the application is being run in development or in + production (use a different `.ini`` file for production than you do for + development). This is just a suggestion for a pattern; any setting name + other than ``media_location`` could be used. + .. index:: single: generating static resource urls single: static resource urls @@ -133,8 +152,8 @@ For example, let's assume you create a set of static declarations like so: config.add_static_view(name='static1', path='mypackage:resources/1') config.add_static_view(name='static2', path='mypackage:resources/2') -These declarations create URL-accessible directories which have URLs which -begin, respectively, with ``/static1`` and ``/static2``. The resources in +These declarations create URL-accessible directories which have URLs that +begin with ``/static1`` and ``/static2``, respectively. The resources in the ``resources/1`` directory of the ``mypackage`` package are consulted when a user visits a URL which begins with ``/static1``, and the resources in the ``resources/2`` directory of the ``mypackage`` package are consulted when a @@ -178,7 +197,7 @@ instead of a view name. For example, the ``name`` argument may be .. code-block:: python :linenos: - config.add_static_view(name='static1', path='mypackage:images') + config.add_static_view(name='http://example.com/images', path='mypackage:images') Under such a configuration, the URL generated by ``static_url`` for resources which begin with ``mypackage:images`` will be prefixed with @@ -206,7 +225,7 @@ The :class:`pyramid.view.static` helper class is used to perform this task. This class creates an object that is capable acting as a :app:`Pyramid` view callable which serves static resources from a directory. For instance, to serve files within a directory located on -your filesystem at ``/path/to/static/dir`` mounted at the URL path +your filesystem at ``/path/to/static/dir`` from the URL path ``/static`` in your application, create an instance of the :class:`pyramid.view.static` class inside a ``static.py`` file in your application root as below. @@ -219,13 +238,10 @@ your application root as below. static_view = static('/path/to/static/dir') .. note:: the argument to :class:`pyramid.view.static` can also be - a relative pathname, e.g. ``my/static`` (meaning relative to the + a "here-relative" pathname, e.g. ``my/static`` (meaning relative to the Python package of the module in which the view is being defined). It can also be a :term:`resource specification` - (e.g. ``anotherpackage:some/subdirectory``) or it can be a - "here-relative" path (e.g. ``some/subdirectory``). If the path is - "here-relative", it is relative to the package of the module in - which the static view is defined. + (e.g. ``anotherpackage:some/subdirectory``). Subsequently, you may wire this view up to be accessible as ``/static`` using the :mod:`pyramid.config.Configurator.add_view` method in your @@ -238,25 +254,33 @@ represents your root object. config.add_view('mypackage.static.static_view', name='static', context='mypackage.models.Root') -In this case, ``mypackage.models.Root`` refers to the class of which your -:app:`Pyramid` application's root object is an instance. +In this case, ``mypackage.models.Root`` refers to the class of your +:app:`Pyramid` application's traversal root object. -You can also omit the ``context`` argument if you want the name ``static`` to -be accessible as the static view against any model. This will also allow -``/static/foo.js`` to work, but it will allow for ``/anything/static/foo.js`` -too, as long as ``anything`` itself is resolvable. +The context argument above limits where the static view is accessible to +URL paths directly under the root object. If you omit the ``context`` +argument, then ``static`` will be accessible as the static view against +any model object in the traversal graph. This will allow +``/static/foo.js`` to work, but it will also allow for +``/anything/static/foo.js`` too, as long as ``anything`` can be +resolved. Note that you cannot use the :func:`pyramid.url.static_url` API to generate URLs against resources made accessible by registering a custom static view. .. warning:: - To ensure that model objects contained in the root don't "shadow" - your static view (model objects take precedence during traversal), - or to ensure that your root object's ``__getitem__`` is never - called when a static resource is requested, you can refer to your - static resources as registered above in URLs as, - e.g. ``/@@static/foo.js``. This is completely equivalent to - ``/static/foo.js``. See :ref:`traversal_chapter` for information + When adding a static view to your root object, you need to be + careful that there are no model objects contained in the + root with the same key as the view name (e.g., ``static``). + Model objects take precedence during traversal, + thus such a name collision will cause the model to "shadow" + your static view. To avoid this issue, and ensure that your + root object's ``__getitem__`` is never + called when a static resource is requested, you can refer to them + unambiguously using the ``@@`` prefix (goggles) in their URLs. + For the above examples you could use '/@@static/foo.js' + instead of '/static/foo.js' to avoid such shadowing. + See :ref:`traversal_chapter` for information about "goggles" (``@@``). diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst index 3d109218e..01729c4bd 100644 --- a/docs/narr/traversal.rst +++ b/docs/narr/traversal.rst @@ -360,7 +360,7 @@ and a :term:`view name`. of path segments that come from ``PATH_INFO`` that are "left over" after traversal has completed. -Once :term:`context` and :term:`view name` and associated attributes +Once :term:`context`, :term:`view name`, and associated attributes such as the :term:`subpath` are located, the job of :term:`traversal` is finished. It passes back the information it obtained to its caller, the :app:`Pyramid` :term:`Router`, which subsequently diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index 5d8dae1c5..c84a5ca06 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -96,7 +96,7 @@ registry`. Here's an example: .. versionchanged:: 1.0a4 Prior to 1.0a4, routes allow for a marker starting with a ``:``, for - example ``/prefix/{one}``. Starting in 1.0a4, this style is deprecated + example ``/prefix/:one/:two``. Starting in 1.0a4, this style is deprecated in favor or ``{}`` usage which allows for additional functionality. .. index:: @@ -179,12 +179,12 @@ during a request. To do so: to service requests that match the route pattern. In this way, we supply a shortcut to the developer. Under the hood, -:app:`Pyramid` still consumes the :term:`context finding` and -:term:`view lookup` subsystems provided by :app:`Pyramid`, but in a -way which does not require that a developer understand either of them -if he doesn't want or need to. It also means that we can allow a -developer to combine :term:`URL dispatch` and :term:`traversal` in -various exceptional cases as documented in :ref:`hybrid_chapter`. +the :term:`context finding` and :term:`view lookup` subsystems +provided by :app:`Pyramid` are still being utilized, but in a way +which does not require a developer to understand either of them in +detail. It also means that we can allow a developer to combine +:term:`URL dispatch` and :term:`traversal` in various exceptional +cases as documented in :ref:`hybrid_chapter`. .. index:: single: route path pattern syntax @@ -263,15 +263,15 @@ To capture both segments, two replacement markers can be used: foo/{name}.{ext} -The literal path ``/foo/biz.html`` will match the above route pattern, and the -match result will be ``{'name': 'biz', 'ext': 'html'}``. This occurs because -the replacement marker ``{name}`` has a literal part of ``.`` between the other -replacement marker ``:ext``. +The literal path ``/foo/biz.html`` will match the above route pattern, +and the match result will be ``{'name': 'biz', 'ext': 'html'}``. This +occurs because the replacement marker ``{name}`` has a literal part of +``.`` (period) between the other replacement marker ``{ext}``. -It is possible to use two replacement markers without any literal characters -between them, for instance ``/{foo}{bar}``. This would be a nonsensical pattern -without specifying a custom regular expression to restrict what a marker -captures. +It is possible to use two replacement markers without any literal +characters between them, for instance ``/{foo}{bar}``. However, this +would be a nonsensical pattern without specifying a custom regular +expression to restrict what each marker captures. Segments must contain at least one character in order to match a segment replacement marker. For example, for the URL ``/abc/``: @@ -281,7 +281,7 @@ segment replacement marker. For example, for the URL ``/abc/``: - ``/{foo}/`` will match. Note that values representing path segments matched with a -``:segment`` match will be url-unquoted and decoded from UTF-8 into +``{segment}`` match will be url-unquoted and decoded from UTF-8 into Unicode within the matchdict. So for instance, the following pattern: @@ -358,7 +358,7 @@ matchdicts: foo/abc/def/a/b/c -> {'baz':'abc', 'bar':'def', 'fizzle': 'a/b/c')} This occurs because the default regular expression for a marker is ``[^/]+`` -which will match everything up to the first ``/``, while ``{filzzle:.*}`` will +which will match everything up to the first ``/``, while ``{fizzle:.*}`` will result in a regular expression match of ``.*`` capturing the remainder into a single value. @@ -368,9 +368,9 @@ a single value. 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. +Route configuration declarations are evaluated in a specific +order when a request enters the system. As a result, the +order of route configuration declarations is very important. The order that routes declarations are evaluated is the order in which they are added to the application at startup time. This is unlike @@ -390,7 +390,7 @@ be added in the following order: members/abc In such a configuration, the ``members/abc`` pattern would *never* be -matched; this is because the match ordering will always match +matched. This is because the match ordering will always match ``members/{def}`` first; the route configuration with ``members/abc`` will never be evaluated. @@ -417,7 +417,7 @@ found via :term:`view lookup`. factory='myproject.models.root_factory') The factory can either be a Python object or a :term:`dotted Python name` (a -string) which points to such a Python oject, as it is above. +string) which points to such a Python object, as it is above. In this way, each route can use a different factory, making it possible to supply a different :term:`context` object to the view @@ -425,8 +425,8 @@ related to each particular route. Supplying a different context for each route is useful when you're trying to use a :app:`Pyramid` :term:`authorization policy` to -provide declarative "context-sensitive" security checks; each context -can maintain a separate :term:`ACL`, as in +provide declarative, "context sensitive" security checks; each context +can maintain a separate :term:`ACL`, as documented in :ref:`using_security_with_urldispatch`. It is also useful when you wish to combine URL dispatch with :term:`traversal` as documented within :ref:`hybrid_chapter`. @@ -1080,12 +1080,14 @@ Redirecting to Slash-Appended Routes ------------------------------------ For behavior like Django's ``APPEND_SLASH=True``, use the -:func:`pyramid.view.append_slash_notfound_view` view as the -:term:`Not Found view` in your application. When this view is the Not -Found view (indicating that no view was found), and any routes have -been defined in the configuration of your application, if the value of -``PATH_INFO`` does not already end in a slash, and if the value of -``PATH_INFO`` *plus* a slash matches any route's pattern, it does an +:func:`pyramid.view.append_slash_notfound_view` view as the :term:`Not +Found view` in your application. Defining this view as the :term:`Not +Found view` is a way to automatically redirect requests where the URL +lacks a trailing slash, but requires one to match the proper route. +When configured, along with at least one other route in your +application, this view will be invoked if the value of ``PATH_INFO`` +does not already end in a slash, and if the value of ``PATH_INFO`` +*plus* a slash matches any route's pattern. In this case it does an HTTP redirect to the slash-appended ``PATH_INFO``. Let's use an example, because this behavior is a bit magical. If the @@ -1098,20 +1100,24 @@ your route configuration looks like so: config.add_route('noslash', 'no_slash', view='myproject.views.no_slash') config.add_route('hasslash', 'has_slash/', view='myproject.views.has_slash') +If a request enters the application with the ``PATH_INFO`` +value of ``/has_slash/``, the second route will match. If a request +enters the application with the ``PATH_INFO`` value of ``/has_slash``, +a route *will* be found by the slash-appending not found view. An HTTP +redirect to ``/has_slash/`` will be returned to the user's browser. + If a request enters the application with the ``PATH_INFO`` value of -``/no_slash``, the first route will match. If a request enters the +``/no_slash``, the first route will match. However, if a request enters the application with the ``PATH_INFO`` value of ``/no_slash/``, *no* route -will match, and the slash-appending "not found" view will *not* find a +will match, and the slash-appending not found view will *not* find a matching route with an appended slash. -However, if a request enters the application with the ``PATH_INFO`` -value of ``/has_slash/``, the second route will match. If a request -enters the application with the ``PATH_INFO`` value of ``/has_slash``, -a route *will* be found by the slash appending notfound view. An HTTP -redirect to ``/has_slash/`` will be returned to the user's browser. +.. warning:: -Note that this will *lose* ``POST`` data information (turning it into -a GET), so you shouldn't rely on this to redirect POST requests. + You **should not** rely on this mechanism to redirect ``POST`` requests. + The redirect of the slash-appending not found view will turn a ``POST`` + request into a ``GET``, losing any ``POST`` data in the original + request. To configure the slash-appending not found view in your application, change the application's startup configuration, adding the following stanza: diff --git a/docs/narr/views.rst b/docs/narr/views.rst index fee341634..8a689be21 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -18,7 +18,7 @@ a request made to your application. that implements a view *callable*, and the process of view *lookup*. -The chapter named :ref:`contextfinding_chapter` describes how, using +The chapter :ref:`contextfinding_chapter` describes how, using information from the :term:`request`, a :term:`context` and a :term:`view name` are computed. But neither the context nor the view name found are very useful unless those elements can eventually be @@ -47,15 +47,13 @@ represents a :app:`Pyramid` :term:`Request` object. A request object encapsulates a WSGI environment as represented to :app:`Pyramid` by the upstream :term:`WSGI` server. -A view callable may always return a :mod:`Pyramid` :term:`Response` object -directly. It may optionally return another arbitrary non-Response value: if a -view callable returns a non-Response result, the result must be converted into -a response by the :term:`renderer` associated with the :term:`view +A view callable can return a :mod:`Pyramid` :term:`Response` object +directly. It may return another arbitrary non-Response value, +however, this return value must be converted into a :term:`Response` +object by the :term:`renderer` associated with the :term:`view configuration` for the view. -View callables can be functions, instances, or classes. View -callables can optionally be defined with an alternate calling -convention. +View callables can be functions, instances, or classes. .. index:: single: view calling convention @@ -67,7 +65,7 @@ Defining a View Callable as a Function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The easiest way to define a view callable is to create a function that -accepts a single argument named ``request`` and which returns a +accepts a single argument named ``request``, and which returns a :term:`Response` object. For example, this is a "hello world" view callable implemented as a function: @@ -97,10 +95,7 @@ created. Subsequently, that instance's ``__call__`` method is invoked with no parameters. Views defined as classes must have the following traits: -- an ``__init__`` method that accepts a ``request`` as its sole - positional argument or an ``__init__`` method that accepts two - arguments: ``request`` and ``context`` as per - :ref:`request_and_context_view_definitions`. +- an ``__init__`` method that accepts a ``request`` argument. - a ``__call__`` method that accepts no parameters and which returns a response. @@ -132,75 +127,74 @@ represent the method expected to return a response, you can use an .. _request_and_context_view_definitions: -Context-And-Request View Callable Definitions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. sidebar:: Context-And-Request View Callable Definitions -Usually, view callables are defined to accept only a single argument: -``request``. However, view callables may alternately be defined as -classes or functions (or any callable) that accept *two* positional -arguments: a :term:`context` as the first argument and a -:term:`request` as the second argument. + Usually, view callables are defined to accept only a single argument: + ``request``. However, view callables may alternately be defined as + classes, functions, or any callable that accept *two* positional + arguments: a :term:`context` as the first argument and a + :term:`request` as the second argument. -The :term:`context` and :term:`request` arguments passed to a view -function defined in this style can be defined as follows: + The :term:`context` and :term:`request` arguments passed to a view + function defined in this style can be defined as follows: -context - An instance of a :term:`context` found via graph :term:`traversal` - or :term:`URL dispatch`. If the context is found via traversal, it - will be a :term:`model` object. + context + An instance of a :term:`context` found via graph :term:`traversal` + or :term:`URL dispatch`. If the context is found via traversal, it + will be a :term:`model` object. -request - A :app:`Pyramid` Request object representing the current WSGI - request. + request + A :app:`Pyramid` Request object representing the current WSGI + request. -The following types work as view callables in this style: + The following types work as view callables in this style: -#. Functions that accept two arguments: ``context``, and ``request``, - e.g.: + #. Functions that accept two arguments: ``context``, and ``request``, + e.g.: - .. code-block:: python - :linenos: + .. code-block:: python + :linenos: - from pyramid.response import Response + from pyramid.response import Response - def view(context, request): - return Response('OK') + def view(context, request): + return Response('OK') -#. Classes that have an ``__init__`` method that accepts ``context, - request`` and a ``__call__`` which accepts no arguments, e.g.: + #. Classes that have an ``__init__`` method that accepts ``context, + request`` and a ``__call__`` which accepts no arguments, e.g.: - .. code-block:: python - :linenos: + .. code-block:: python + :linenos: - from pyramid.response import Response + from pyramid.response import Response - class view(object): - def __init__(self, context, request): - self.context = context - self.request = request + class view(object): + def __init__(self, context, request): + self.context = context + self.request = request - def __call__(self): - return Response('OK') + def __call__(self): + return Response('OK') -#. Arbitrary callables that have a ``__call__`` method that accepts - ``context, request``, e.g.: + #. Arbitrary callables that have a ``__call__`` method that accepts + ``context, request``, e.g.: - .. code-block:: python - :linenos: + .. code-block:: python + :linenos: - from pyramid.response import Response + from pyramid.response import Response - class View(object): - def __call__(self, context, request): - return Response('OK') - view = View() # this is the view callable + class View(object): + def __call__(self, context, request): + return Response('OK') + view = View() # this is the view callable -This style of calling convention is most useful for :term:`traversal` -based applications, where the context object is frequently used within -the view callable code itself. + This style of calling convention is most useful for :term:`traversal` + based applications, where the context object is frequently used within + the view callable code itself. -No matter which view calling convention is used, the view code always -has access to the context via ``request.context``. + No matter which view calling convention is used, the view code always + has access to the context via ``request.context``. .. index:: single: view response @@ -288,8 +282,8 @@ and renderers which use templating systems. See also .. _http_redirect: -Using a View Callable to Do A HTTP Redirect -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Using a View Callable to Do an HTTP Redirect +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can issue an HTTP redirect from within a view by returning a particular kind of response. @@ -308,6 +302,19 @@ See :mod:`pyramid.httpexceptions` for the documentation for the ``HTTPFound`` exception; it also includes other response types that imply other HTTP response codes, such as ``HTTPUnauthorized`` for ``401 Unauthorized``. +.. note:: + + Although exception types from the :mod:`pyramid.httpexceptions` module are + in fact bona fide Python :class:`Exception` types, the :app:`Pyramid` view + machinery expects them to be *returned* by a view callable rather than + *raised*. + + It is possible, however, in Python 2.5 and above, to configure an + *exception view* to catch these exceptions, and return an appropriate + :class:`pyramid.response.Response`. The simplest such view could just + catch and return the original exception. See :ref:`exception_views` for + more details. + .. index:: single: renderer single: view renderer @@ -379,7 +386,7 @@ Additional renderers can be added to the system as necessary (see Built-In Renderers ~~~~~~~~~~~~~~~~~~ -Several built-in "renderers" exist in :app:`Pyramid`. These +Several built-in renderers exist in :app:`Pyramid`. These renderers can be used in the ``renderer`` attribute of view configurations. @@ -429,14 +436,13 @@ attributes by attaching properties to the request. See ``json``: JSON Renderer +++++++++++++++++++++++ -The ``json`` renderer is a renderer which renders view callable -results to :term:`JSON`. If a view callable returns a non-Response -object it is called. It passes the return value through the +The ``json`` renderer renders view callable +results to :term:`JSON`. It passes the return value through the ``json.dumps`` standard library function, and wraps the result in a response object. It also sets the response content-type to ``application/json``. -Here's an example of a view that returns a dictionary. If the +Here's an example of a view that returns a dictionary. Since the ``json`` renderer is specified in the configuration for this view, the view will render the returned dictionary to a JSON serialization: @@ -561,19 +567,21 @@ attaching properties to the request. See ``*.mak`` or ``*.mako``: Mako Template Renderer +++++++++++++++++++++++++++++++++++++++++++++++ -The ``Mako`` template renderer is a renderer which renders a Mako template. +The ``Mako`` template renderer renders views using a Mako template. When used, the view must return a Response object or a Python *dictionary*. The dictionary items will then be used in the global template space. If the -view callable returns anything but a Response object or a dictionary, an error +view callable returns anything but a Response object, or a dictionary, an error will be raised. -When using the ``renderer`` attribute to specify a Mako template, the template -can be specified in two ways. First, a relative path can be used to name a -Mako template relative to the configured Mako template directories. Second, a -:term:`resource specification` can be used to locate a template to render. -These two styles of naming a template to render also carry through to Mako -templates, so that Mako template's can inherit using a :term:`resource -specification` if desired. +When using a ``renderer`` argument to a :term:`view configuration` to +specify a Mako template, the value of the ``renderer`` may be a path +relative to the ``mako.directories`` setting (e.g. +``some/template.mak``) or, alternately, it may be a :term:`resource +specification` (e.g. ``apackage:templates/sometemplate.mak``). Mako +templates may internally inherit other Mako templates using a relative +filename or a :term:`resource specification` as desired. + +XXX Further explanation or link to mako inheritance info Here's an example view configuration which uses a relative path: @@ -620,14 +628,13 @@ additional :ref:`mako_template_renderer_settings`. Varying Attributes of Rendered Responses ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Before a response that is constructed as the result of the use of a -:term:`renderer` is returned to :app:`Pyramid`, several attributes -of the request are examined which have the potential to influence -response behavior. +Before a response constructed by a :term:`renderer` is returned to +:app:`Pyramid`, several attributes of the request are examined which +have the potential to influence response behavior. View callables that don't directly return a response should set these -values on the ``request`` object via ``setattr`` within the view -callable to influence associated response attributes. +attributes on the ``request`` object via ``setattr`` during their +execution, to influence associated response attributes. ``response_content_type`` Defines the content-type of the resulting response, @@ -678,7 +685,7 @@ Adding and Overriding Renderers New templating systems and serializers can be associated with :app:`Pyramid` renderer names. To this end, configuration declarations can be made which -override an existing :term:`renderer factory` and which add a new renderer +override an existing :term:`renderer factory`, and which add a new renderer factory. Renderers can be registered imperatively using the @@ -707,10 +714,10 @@ to such an object. Adding a New Renderer +++++++++++++++++++++ -You may a new renderer by creating and registering a :term:`renderer +You may add a new renderer by creating and registering a :term:`renderer factory`. -A renderer factory implementation is usually a class which has the +A renderer factory implementation is typically a class with the following interface: .. code-block:: python @@ -739,8 +746,8 @@ factory constructor is available as :class:`pyramid.interfaces.IRendererInfo`. There are essentially two different kinds of renderer factories: -- A renderer factory which expects to accept a :term:`resource specification` - or an absolute path as the ``name`` attribute of the ``info`` object fed to +- A renderer factory which expects to accept a :term:`resource specification`, + or an absolute path, as the ``name`` attribute of the ``info`` object fed to its constructor. These renderer factories are registered with a ``name`` value that begins with a dot (``.``). These types of renderer factories usually relate to a file on the filesystem, such as a template. @@ -770,10 +777,11 @@ Here's an example of the registration of a simple renderer factory via config.add_renderer(name='amf', factory='my.package.MyAMFRenderer') -Adding the above code to your application startup configuration will allow -you to use the ``my.package.MyAMFRenderer`` renderer factory implementation -in view configurations by referring to it as ``amf`` in the ``renderer`` -attribute of a :term:`view configuration`: +Adding the above code to your application startup configuration will +allow you to use the ``my.package.MyAMFRenderer`` renderer factory +implementation in view configurations. Your application can use this +renderer by specifying ``amf`` in the ``renderer`` attribute of a +:term:`view configuration`: .. code-block:: python :linenos: @@ -784,13 +792,12 @@ attribute of a :term:`view configuration`: def myview(request): return {'Hello':'world'} -At startup time, when a :term:`view configuration` is encountered -which has a ``name`` argument that does not contain a dot, such as the -above ``amf`` is encountered, the full value of the ``name`` attribute -is used to construct a renderer from the associated renderer factory. -In this case, the view configuration will create an instance of an -``AMFRenderer`` for each view configuration which includes ``amf`` as -its renderer value. The ``name`` passed to the ``AMFRenderer`` +At startup time, when a :term:`view configuration` is encountered, which +has a ``name`` attribute that does not contain a dot, the full ``name`` +value is used to construct a renderer from the associated renderer +factory. In this case, the view configuration will create an instance +of an ``AMFRenderer`` for each view configuration which includes ``amf`` +as its renderer value. The ``name`` passed to the ``AMFRenderer`` constructor will always be ``amf``. Here's an example of the registration of a more complicated renderer @@ -816,17 +823,17 @@ the ``renderer`` attribute of a :term:`view configuration`: def myview(request): return {'Hello':'world'} -When a :term:`view configuration` which has a ``name`` attribute that does -contain a dot, such as ``templates/mytemplate.jinja2`` above is encountered -at startup time, the value of the name attribute is split on its final dot. -The second element of the split is typically the filename extension. This -extension is used to look up a renderer factory for the configured view. -Then the value of ``renderer`` is passed to the factory to create a renderer -for the view. In this case, the view configuration will create an instance -of a ``Jinja2Renderer`` for each view configuration which includes anything -ending with ``.jinja2`` as its ``renderer`` value. The ``name`` passed to -the ``Jinja2Renderer`` constructor will be whatever the user passed as -``renderer=`` to the view configuration. +When a :term:`view configuration` is encountered at startup time, which +has a ``name`` attribute that does contain a dot, the value of the name +attribute is split on its final dot. The second element of the split is +typically the filename extension. This extension is used to look up a +renderer factory for the configured view. Then the value of +``renderer`` is passed to the factory to create a renderer for the view. +In this case, the view configuration will create an instance of a +``Jinja2Renderer`` for each view configuration which includes anything +ending with ``.jinja2`` in its ``renderer`` value. The ``name`` passed +to the ``Jinja2Renderer`` constructor will be the full value that was +set as ``renderer=`` in the view configuration. See also :ref:`renderer_directive` and :meth:`pyramid.config.Configurator.add_renderer`. @@ -861,9 +868,9 @@ After you do this, the :term:`renderer factory` in ``mypackage.pt_renderer`` will be used to render templates which end in ``.pt``, replacing the default Chameleon ZPT renderer. -To associate a *default* renderer with *all* view configurations (even ones -which do not possess a ``renderer`` attribute), use a variation on the -following (ie. pass ``None`` as the ``name`` attribute to the renderer tag): +To associate a *default* renderer with *all* view configurations (even +ones which do not possess a ``renderer`` attribute), pass ``None`` as +the ``name`` attribute to the renderer tag: .. code-block:: python :linenos: @@ -970,25 +977,24 @@ The above exception view names the ``route_name`` of ``home``, meaning that it will only be called when the route matched has a name of ``home``. You can therefore have more than one exception view for any given exception in the system: the "most specific" one will be called -when the set of request circumstances which match the view -registration. +when the set of request circumstances match the view registration. -The only view predicate that cannot be not be used successfully when -creating an exception view configuration is ``name``. The name used -to look up an exception view is always the empty string. Views -registered as exception views which have a name will be ignored. +The only view predicate that cannot be used successfully when creating +an exception view configuration is ``name``. The name used to look up +an exception view is always the empty string. Views registered as +exception views which have a name will be ignored. .. note:: - Normal (non-exception) views registered against a context which + Normal (i.e., non-exception) views registered against a context which inherits from :exc:`Exception` will work normally. When an - exception view configuraton is processed, *two* views are + exception view configuration is processed, *two* views are registered. One as a "normal" view, the other as an "exception" view. This means that you can use an exception as ``context`` for a normal view. -The feature can be used with any view registration mechanism -(``@view_config`` decorator, ZCML, or imperative ``add_view`` styles). +Exception views can be configured with any view registration mechanism: +``@view_config`` decorator, ZCML, or imperative ``add_view`` styles. .. index:: single: unicode, views, and forms @@ -1010,19 +1016,29 @@ implementations, and handling form submission data is a property of the request implementation. Understanding WebOb's request API is the key to understanding how to process form submission data. -There are some defaults that you need to be aware of when trying to handle form -submission data in a :app:`Pyramid` view. Because having high-order -(non-ASCII) characters in data contained within form submissions is exceedingly -common, and because the UTF-8 encoding is the most common encoding used on the -web for non-ASCII character data, and because working and storing Unicode -values is much saner than working with and storing bytestrings, :app:`Pyramid` +There are some defaults that you need to be aware of when trying to +handle form submission data in a :app:`Pyramid` view. Having high-order +(i.e., non-ASCII) characters in data contained within form submissions +is exceedingly common, and the UTF-8 encoding is the most common +encoding used on the web for character data. Since Unicode values are +much saner than working with and storing bytestrings, :app:`Pyramid` configures the :term:`WebOb` request machinery to attempt to decode form -submission values into Unicode from the UTF-8 character set implicitly. This -implicit decoding happens when view code obtains form field values via the -``request.params``, ``request.GET``, or ``request.POST`` APIs (see -:ref:`request_module` for details about these APIs). +submission values into Unicode from UTF-8 implicitly. +This implicit decoding happens when view code obtains form field values +via the ``request.params``, ``request.GET``, or ``request.POST`` APIs +(see :ref:`request_module` for details about these APIs). -For example, let's assume that the following form page is served up to +.. note:: + Many people find the difference between Unicode and UTF-8 confusing. + Unicode is a standard for representing text that supports most of the + world's writing systems. However, there are many ways that Unicode + data can be encoded into bytes for transmittal and storage. UTF-8 is + a specific encoding for Unicode, that is backwards-compatible with + ASCII. This makes UTF-8 very convenient for encoding data where a + large subset of that data is ASCII characters, which is largely true + on the web. UTF-8 is also the standard character encoding for URLs. + +As an example, let's assume that the following form page is served up to a browser client, and its ``action`` points at some :app:`Pyramid` view code: @@ -1069,22 +1085,24 @@ decode already-decoded (``unicode``) values obtained from firstname = request.params['firstname'].decode('utf-8') lastname = request.params['lastname'].decode('utf-8') -For implicit decoding to work reliably, you should ensure that every form you -render that posts to a :app:`Pyramid` view is rendered via a response that has -a ``;charset=UTF-8`` in its ``Content-Type`` header; or, as in the form above, -with a ``meta http-equiv`` tag that implies that the charset is UTF-8 within -the HTML ``head`` of the page containing the form. This must be done -explicitly because all known browser clients assume that they should encode -form data in the character set implied by ``Content-Type`` value of the -response containing the form when subsequently submitting that form; there is -no other generally accepted way to tell browser clients which charset to use to -encode form data. If you do not specify an encoding explicitly, the browser -client will choose to encode form data in its default character set before -submitting it. The browser client may have a non-UTF-8 default encoding. If -such a request is handled by your view code, when the form submission data is -encoded in a non-UTF8 charset, eventually the request code accessed within your -view will throw an error when it can't decode some high-order character encoded -in another character set within form data e.g. when +For implicit decoding to work reliably, you should ensure that every +form you render that posts to a :app:`Pyramid` view explicitly defines a +charset encoding of UTF-8. This can be done via a response that has a +``;charset=UTF-8`` in its ``Content-Type`` header; or, as in the form +above, with a ``meta http-equiv`` tag that implies that the charset is +UTF-8 within the HTML ``head`` of the page containing the form. This +must be done explicitly because all known browser clients assume that +they should encode form data in the same character set implied by +``Content-Type`` value of the response containing the form when +subsequently submitting that form. There is no other generally accepted +way to tell browser clients which charset to use to encode form data. +If you do not specify an encoding explicitly, the browser client will +choose to encode form data in its default character set before +submitting it, which may not be UTF-8 as the server expects. If a +request containing form data encoded in a non-UTF8 charset is handled by +your view code, eventually the request code accessed within your view +will throw an error when it can't decode some high-order character +encoded in another character set within form data, e.g., when ``request.params['somename']`` is accessed. If you are using the :class:`pyramid.response.Response` class to generate a @@ -1092,14 +1110,14 @@ response, or if you use the ``render_template_*`` templating APIs, the UTF-8 charset is set automatically as the default via the ``Content-Type`` header. If you return a ``Content-Type`` header without an explicit charset, a request will add a ``;charset=utf-8`` trailer to the ``Content-Type`` header value for -you for response content types that are textual (e.g. ``text/html``, +you, for response content types that are textual (e.g. ``text/html``, ``application/xml``, etc) as it is rendered. If you are using your own response object, you will need to ensure you do this yourself. .. note:: Only the *values* of request params obtained via ``request.params``, ``request.GET`` or ``request.POST`` are decoded to Unicode objects implicitly in the :app:`Pyramid` default - configuration. The keys are still strings. + configuration. The keys are still (byte) strings. .. index:: single: view configuration @@ -1112,7 +1130,7 @@ View Configuration: Mapping a Context to a View A developer makes a :term:`view callable` available for use within a :app:`Pyramid` application via :term:`view configuration`. A view configuration associates a view callable with a set of statements -about the set of circumstances which must be true for the view +that determine the set of circumstances which must be true for the view callable to be invoked. A view configuration statement is made about information present in @@ -1246,6 +1264,10 @@ Non-Predicate Arguments Predicate Arguments +++++++++++++++++++ +These arguments modify view lookup behavior. In general, the more +predicate arguments that are supplied, the more specific, and narrower +the usage of the configured view. + ``name`` The :term:`view name` required to match this view callable. Read :ref:`traversal_chapter` to understand the concept of a view name. @@ -1254,7 +1276,7 @@ Predicate Arguments default view). ``context`` - An object representing Python class that the :term:`context` must be + An object representing a Python class that the :term:`context` must be an instance of, *or* the :term:`interface` that the :term:`context` must provide in order for this view to be found and called. This predicate is true when the :term:`context` is an instance of the @@ -1271,14 +1293,15 @@ Predicate Arguments This value must match the ``name`` of a :term:`route configuration` declaration (see :ref:`urldispatch_chapter`) that must match before this view will be called. Note that the ``route`` configuration - referred to by ``route_name`` usually has a ``*traverse`` token in - the value of its ``pattern``, representing a part of the path that will - be used by :term:`traversal` against the result of the route's + referred to by ``route_name`` will usually have a ``*traverse`` token + in the value of its ``pattern``, representing a part of the path that + will be used by :term:`traversal` against the result of the route's :term:`root factory`. If ``route_name`` is not supplied, the view callable will be have a - chance of being invoked for when the :term:`triad` includes a - request object that does not indicate it matched a route. + chance of being invoked if no other route was matched. This is when + the request object of the :term:`triad` does not indicate it matched + any configured route. ``request_type`` This value should be an :term:`interface` that the :term:`request` @@ -1319,9 +1342,10 @@ Predicate Arguments ``containment`` This value should be a reference to a Python class or - :term:`interface` that a parent object in the :term:`lineage` must - provide in order for this view to be found and called. The nodes in - your object graph must be "location-aware" to use this feature. + :term:`interface` that a parent object in the context's + :term:`lineage` must provide in order for this view to be found and + called. The nodes in your object graph must be "location-aware" to + use this feature. If ``containment`` is not supplied, the interfaces and classes in the lineage are not considered when deciding whether or not to @@ -1480,11 +1504,13 @@ All arguments to ``view_config`` may be omitted. For example: Such a registration as the one directly above implies that the view name will be ``my_view``, registered with a ``context`` argument that matches any model type, using no permission, registered against -requests with any request method / request type / request param / -route name / containment. +requests with any request method, request type, request param, +route name, or containment. -The mere existence of a ``@view_config`` decorator doesn't suffice to perform -view configuration. To make :app:`Pyramid` process your +The mere existence of a ``@view_config`` decorator doesn't suffice to +perform view configuration. All that the decorator does is "annotate" +the function with your configuration declarations, it doesn't process +them. To make :app:`Pyramid` process your :class:`pyramid.view.view_config` declarations, you *must* do use the ``scan`` method of a :class:`pyramid.config.Configurator`: @@ -1602,7 +1628,7 @@ When the decorator is used against a class method, a view is registered for the *class*, so the class constructor must accept an argument list in one of two forms: either it must accept a single argument ``request`` or it must accept two arguments, ``context, -request`` as per :ref:`request_and_context_view_definitions`. +request``. The method which is decorated must return a :term:`response` or it must rely on a :term:`renderer` to generate one. @@ -1721,12 +1747,12 @@ in such a way that the interface is attached to it. alsoProvides(hello, IHello) return hello -Regardless of how you associate an interface with a model instance or a model +Regardless of how you associate an interface, with a model instance, or a model class, the resulting code to associate that interface with a view callable is the same. Assuming the above code that defines an ``IHello`` interface lives in the root of your application, and its module is named "models.py", the -below interface declaration will associate the -``mypackage.views.hello_world`` view with models that implement (aka provide) +interface declaration below will associate the +``mypackage.views.hello_world`` view with models that implement, or provide, this interface. .. code-block:: python @@ -1741,11 +1767,13 @@ Any time a model that is determined to be the :term:`context` provides this interface, and a view named ``hello.html`` is looked up against it as per the URL, the ``mypackage.views.hello_world`` view callable will be invoked. -Note that views registered against a model class take precedence over views -registered for any interface the model class implements when an ambiguity -arises. If a view is registered for both the class type of the context and -an interface implemented by the context's class, the view registered for the -context's class will "win". +Note, in cases where a view is registered against a model class, and a +view is also registered against an interface that the model class +implements, an ambiguity arises. Views registered for the model class +take precedence over any views registered for any interface the model +class implements. Thus, if a view is registered for both the class type +of the context and an interface implemented by the context's class, the +view registered for the context's class will "win". For more information about defining models with interfaces for use within view configuration, see :ref:`models_which_implement_interfaces`. @@ -1759,12 +1787,22 @@ view configuration, see :ref:`models_which_implement_interfaces`. Configuring View Security ~~~~~~~~~~~~~~~~~~~~~~~~~ +<<<<<<< HEAD +If an :term:`authorization policy` is active, any :term:`permission` +attached to a :term:`view configuration` found during view lookup will +be verified. This will ensure that the currently authenticated user +possesses that permission against the :term:`context` before the view +function is actually called. Here's an example of specifying a +permission in a view configuration using +:meth:`pyramid.configuration.Configurator.add_view`: +======= If a :term:`authorization policy` is active, any :term:`permission` attached to a :term:`view configuration` found during view lookup will be consulted to ensure that the currently authenticated user possesses that permission against the :term:`context` before the view function is actually called. Here's an example of specifying a permission in a view configuration using :meth:`pyramid.config.Configurator.add_view`: +>>>>>>> fee38663daccc0130d0c34dbc5a14e67bef2e183 .. code-block:: python :linenos: @@ -1774,11 +1812,11 @@ Here's an example of specifying a permission in a view configuration using config.add_view('myproject.views.add_entry', name='add.html', context='myproject.models.IBlog', permission='add') -When an authentication policy is enabled, this view will be protected with -the ``add`` permission. The view will *not be called* if the user does not -possess the ``add`` permission relative to the current :term:`context` and an -authorization policy is enabled. Instead the :term:`forbidden view` result -will be returned to the client as per :ref:`protecting_views`. +When an :term:`authorization policy` is enabled, this view will be +protected with the ``add`` permission. The view will *not be called* if +the user does not possess the ``add`` permission relative to the current +:term:`context`. Instead the :term:`forbidden view` result will be +returned to the client as per :ref:`protecting_views`. .. index:: single: view lookup @@ -1792,7 +1830,7 @@ View Lookup and Invocation finding an invoking a :term:`view callable`. The view lookup subsystem is passed a :term:`context`, a :term:`view name`, and the :term:`request` object. These three bits of information are referred -to within this chapter as a :term:`triad`. +to within this chapter as the :term:`triad`. :term:`View configuration` information stored within in the :term:`application registry` is compared against a triad by the view @@ -1817,7 +1855,7 @@ view is found, or no view can be matched up with the request. The first view with a set of predicates all of which match the request environment will be invoked. -If no view can be found which has predicates which allow it to be +If no view can be found with predicates which allow it to be matched up with the request, :app:`Pyramid` will return an error to the user's browser, representing a "not found" (404) page. See :ref:`changing_the_notfound_view` for more information about changing @@ -1839,5 +1877,5 @@ misconfiguration. To debug these errors, use the configuration file setting. Details of why a view was not found will be printed to ``stderr``, and the browser representation of the error will include the same information. See :ref:`environment_chapter` for -more information about how and where to set these values. +more information about how, and where to set these values. diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst index c4805df8d..83d096a57 100644 --- a/docs/narr/webob.rst +++ b/docs/narr/webob.rst @@ -111,8 +111,8 @@ Special Attributes Added to the Request by :app:`Pyramid` In addition to the standard :term:`WebOb` attributes, :app:`Pyramid` adds special attributes to every request: ``context``, ``registry``, -``root``, ``subpath``, ``traversed``, ``view_name``, ``virtual_root`` -, ``virtual_root_path``, ``session``, and ``tmpl_context``. These +``root``, ``subpath``, ``traversed``, ``view_name``, ``virtual_root``, +``virtual_root_path``, ``session``, and ``tmpl_context``. These attributes are documented further within the :class:`pyramid.request.Request` API documentation. @@ -183,7 +183,7 @@ only a few you'll use often: ``req.get_response(wsgi_application)``: This method calls the given WSGI application with this request, and returns a `Response`_ object. You can also use this for - subrequests or testing. + subrequests, or testing. .. index:: single: request (and unicode) @@ -203,8 +203,8 @@ attribute. If it is set, then ``req.POST``, ``req.GET``, ``req.params``, and ``req.cookies`` will contain unicode strings. Each has a -corresponding ``req.str_*`` (like ``req.str_POST``) that is always -``str`` and never unicode. +corresponding ``req.str_*`` (e.g., ``req.str_POST``) that is always +a ``str``, and never unicode. More Details ++++++++++++ @@ -213,9 +213,9 @@ More detail about the request object API is available in: - The :class:`pyramid.request.Request` API documentation. -- The `WebOb documentation <http://pythonpaste.org/webob>`_ . All +- The `WebOb documentation <http://pythonpaste.org/webob>`_. All methods and attributes of a ``webob.Request`` documented within the - WebOb documentation will work against request objects created by + WebOb documentation will work with request objects created by :app:`Pyramid`. .. index:: @@ -231,8 +231,9 @@ for its original location: ``webob.Response``. A response object has three fundamental parts: ``response.status``: - The response code plus message, like ``'200 OK'``. To set the - code without the reason, use ``response.status_int = 200``. + The response code plus reason message, like ``'200 OK'``. To set + the code without a message, use ``status_int``, i.e.: + ``response.status_int = 200``. ``response.headerlist``: A list of all the headers, like ``[('Content-Type', @@ -325,7 +326,7 @@ Exception Responses To facilitate error responses like ``404 Not Found``, the module :mod:`webob.exc` contains classes for each kind of error response. These -include boring but appropriate error bodies. The exceptions exposed by this +include boring, but appropriate error bodies. The exceptions exposed by this module, when used under :app:`Pyramid`, should be imported from the :mod:`pyramid.httpexceptions` "facade" module. This import location is merely a facade for the original location of these exceptions: ``webob.exc``. |
