docs/glossary.rst | ●●●●● patch | view | raw | blame | history | |
docs/index.rst | ●●●●● patch | view | raw | blame | history | |
docs/latexindex.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/csrf.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/firstapp.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/flash.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/forms.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/renderers.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/sessions.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/traversal.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/urldispatch.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/viewconfig.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/views.rst | ●●●●● patch | view | raw | blame | history |
docs/glossary.rst
@@ -112,14 +112,14 @@ about :app:`Pyramid` view callables. view configuration View configuration is the act of associating a :term:`view callable` with configuration information. This configuration information helps map a given :term:`request` to a particular view callable and it can influence the response of a view callable. :app:`Pyramid` views can be configured via :term:`imperative configuration`, :term:`ZCML` or by a special ``@view_config`` decorator coupled with a :term:`scan`. See :ref:`views_chapter` for more information about view configuration. View configuration is the act of associating a :term:`view callable` with configuration information. This configuration information helps map a given :term:`request` to a particular view callable and it can influence the response of a view callable. :app:`Pyramid` views can be configured via :term:`imperative configuration`, :term:`ZCML` or by a special ``@view_config`` decorator coupled with a :term:`scan`. See :ref:`view_config_chapter` for more information about view configuration. view name The "URL name" of a view, e.g ``index.html``. If a view is docs/index.rst
@@ -44,12 +44,11 @@ narr/views narr/renderers narr/templates narr/viewconfig narr/resources narr/assets narr/webob narr/sessions narr/flash narr/csrf narr/security narr/hybrid narr/i18n @@ -64,6 +63,7 @@ narr/router narr/threadlocals narr/zca narr/forms Tutorials ========= docs/latexindex.rst
@@ -37,12 +37,11 @@ narr/views narr/renderers narr/templates narr/viewconfig narr/resources narr/assets narr/webob narr/sessions narr/flash narr/csrf narr/security narr/hybrid narr/i18n @@ -58,6 +57,7 @@ narr/startup narr/threadlocals narr/zca narr/forms .. _tutorials: docs/narr/csrf.rst
File was deleted docs/narr/firstapp.rst
@@ -323,7 +323,7 @@ see :class:`pyramid.config.Configurator` . For more information about :term:`view configuration`, see :ref:`views_chapter`. :ref:`view_config_chapter`. An example of using *declarative* configuration (:term:`ZCML`) instead of imperative configuration to create a similar "hello world" is available docs/narr/flash.rst
File was deleted docs/narr/forms.rst
New file @@ -0,0 +1,126 @@ .. _forms_chapter: .. index:: single: unicode, views, and forms single: forms, views, and unicode single: views, forms, and unicode Form Handling ============= Handling Form Submissions in View Callables (Unicode and Character Set Issues) ------------------------------------------------------------------------------ Most web applications need to accept form submissions from web browsers and various other clients. In :app:`Pyramid`, form submission handling logic is always part of a :term:`view`. For a general overview of how to handle form submission data using the :term:`WebOb` API, see :ref:`webob_chapter` and `"Query and POST variables" within the WebOb documentation <http://pythonpaste.org/webob/reference.html#query-post-variables>`_. :app:`Pyramid` defers to WebOb for its request and response 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. 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 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). .. 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 transit 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: .. code-block:: xml :linenos: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> </head> <form method="POST" action="myview"> <div> <input type="text" name="firstname"/> </div> <div> <input type="text" name="lastname"/> </div> <input type="submit" value="Submit"/> </form> </html> The ``myview`` view code in the :app:`Pyramid` application *must* expect that the values returned by ``request.params`` will be of type ``unicode``, as opposed to type ``str``. The following will work to accept a form post from the above form: .. code-block:: python :linenos: def myview(request): firstname = request.params['firstname'] lastname = request.params['lastname'] But the following ``myview`` view code *may not* work, as it tries to decode already-decoded (``unicode``) values obtained from ``request.params``: .. code-block:: python :linenos: def myview(request): # the .decode('utf-8') will break below if there are any high-order # characters in the firstname or lastname 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 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 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``, ``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 (byte) strings. docs/narr/renderers.rst
@@ -3,18 +3,10 @@ Renderers ========= In the :ref:`views_chapter` chapter, we said that a view callable must return a :term:`Response` object. We lied. A :term:`renderer` is a service that attempts to convert a non-Response return value of a function, class, or instance that acts as a :term:`view callable` to a :term:`Response` object. Overview -------- A view needn't *always* return a Response object. If a view happens to return something which does not implement the Pyramid Response interface, :app:`Pyramid` will attempt to use a :term:`renderer` to construct a response. For example: A view needn't *always* return a :term:`Response` object. If a view happens to return something which does not implement the Pyramid Response interface, :app:`Pyramid` will attempt to use a :term:`renderer` to construct a response. For example: .. code-block:: python :linenos: docs/narr/sessions.rst
@@ -3,12 +3,17 @@ .. _sessions_chapter: Session Objects =============== Sessions ======== A :term:`session` is a namespace which is valid for some period of continual activity that can be used to represent a user's interaction with a web application. This chapter describes how to configure sessions, what session implementations :app:`Pyramid` provides out of the box, how to store and retrieve data from sessions, and two session-specific features: flash messages, and cross-site request forgery attack prevention. .. _using_the_default_session_factory: @@ -32,7 +37,7 @@ representation of the session is fewer than 4000. This is suitable only for very small data sets. It is, however, digitally signed, and thus its data cannot easily be It is digitally signed, however, and thus its data cannot easily be tampered with. You can configure this session factory in your :app:`Pyramid` @@ -113,7 +118,7 @@ Some gotchas: - Keys and values of session data must be *pickleable*. This means, typically, that they must be instances of basic types of objects, typically, that they are instances of basic types of objects, such as strings, lists, dictionaries, tuples, integers, etc. If you place an object in a session data key or value that is not pickleable, an error will be raised when the session is serialized. @@ -162,3 +167,176 @@ :class:`pyramid.interfaces.ISession`. You might use the cookie implementation in the :mod:`pyramid.session` module as inspiration. .. index:: single: flash messages Flash Messages -------------- "Flash messages" are simply a queue of message strings stored in the :term:`session`. To use flash messaging, you must enable a :term:`session factory` as described in :ref:`using_the_default_session_factory` or :ref:`using_alternate_session_factories`. Flash messaging has two main uses: to display a status message only once to the user after performing an internal redirect, and to allow generic code to log messages for single-time display without having direct access to an HTML template. The user interface consists of a number of methods of the :term:`session` object. Using the ``session.flash`` Method ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To add a message to a flash message queue, use a session object's ``flash()`` method: .. code-block:: python request.session.flash('mymessage') The ``flash()`` method appends a message to a flash queue, creating the queue if necessary. ``flash()`` accepts three arguments: .. method:: flash(message, queue='', allow_duplicate=True) The ``message`` argument is required. It represents a message you wish to later display to a user. It is usually a string but the ``message`` you provide is not modified in any way. The ``queue`` argument allows you to choose a queue to which to append the message you provide. This can be used to push different kinds of messages into flash storage for later display in different places on a page. You can pass any name for your queue, but it must be a string. Each queue is independent, and can be popped by ``pop_flash()`` or examined via ``peek_flash()`` separately. ``queue`` defaults to the empty string. The empty string represents the default flash message queue. .. code-block:: python request.session.flash(msg, 'myappsqueue') The ``allow_duplicate`` argument defaults to ``True``. If this is ``False``, and you attempt to add a message value which is already present in the queue, it will not be added. Using the ``session.pop_flash`` Method ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Once one or more messages have been added to a flash queue by the ``session.flash()`` API, the ``session.pop_flash()`` API can be used to pop an entire queue and return it for use. To pop a particular queue of messages from the flash object, use the session object's ``pop_flash()`` method. This returns a list of the messages that were added to the flash queue, and empties the queue. .. method:: pop_flash(queue='') .. code-block:: python :linenos: >>> request.session.flash('info message') >>> request.session.pop_flash() ['info message'] Calling ``session.pop_flash()`` again like above without a corresponding call to ``session.flash()`` will return an empty list, because the queue has already been popped. .. code-block:: python :linenos: >>> request.session.flash('info message') >>> request.session.pop_flash() ['info message'] >>> request.session.pop_flash() [] Using the ``session.peek_flash`` Method ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Once one or more messages has been added to a flash queue by the ``session.flash()`` API, the ``session.peek_flash()`` API can be used to "peek" at that queue. Unlike ``session.pop_flash()``, the queue is not popped from flash storage. .. method:: peek_flash(queue='') .. code-block:: python :linenos: >>> request.session.flash('info message') >>> request.session.peek_flash() ['info message'] >>> request.session.peek_flash() ['info message'] >>> request.session.pop_flash() ['info message'] >>> request.session.peek_flash() [] .. index:: single: preventing cross-site request forgery attacks single: cross-site request forgery attacks, prevention Preventing Cross-Site Request Forgery Attacks --------------------------------------------- `Cross-site request forgery <http://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks are a phenomenon whereby a user with an identity on your website might click on a URL or button on another website which unwittingly redirects the user to your application to perform some command that requires elevated privileges. You can avoid most of these attacks by making sure that the correct *CSRF token* has been set in an :app:`Pyramid` session object before performing any actions in code which requires elevated privileges that is invoked via a form post. To use CSRF token support, you must enable a :term:`session factory` as described in :ref:`using_the_default_session_factory` or :ref:`using_alternate_session_factories`. Using the ``session.new_csrf_token`` Method ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To add a CSRF token to the session, use the ``session.new_csrf_token()`` method. .. code-block:: python token = request.session.new_csrf_token() The ``new_csrf_token()`` method accepts no arguments. It returns a *token* string, which will be opaque and randomized. This token will also be set into the session, awaiting pickup by the ``session.get_csrf_token()`` method. You can subsequently use the returned token as the value of a hidden field in a form that posts to a method that requires elevated privileges. The handler for the form post should use ``session.get_csrf_token()`` (explained below) to obtain the current CSRF token related to the user from the session, and compare it to the value of the hidden form field. Using the ``session.get_csrf_token`` Method ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To get the current CSRF token from the session, use the ``session.get_csrf_token()`` method. .. code-block:: python token = request.session.get_csrf_token() The ``get_csrf_token()`` method accepts no arguments. It returns the "current" *token* string generated by the last call to ``session.new_csrf_token()``. You can then use it to compare against the token provided within form post hidden value data. For example, if your form rendering included the CSRF token obtained via ``session.new_csrf_token()`` as a hidden input field named ``csrf_token()``: .. code-block:: python :linenos: token = request.session.get_csrf_token() if token != request.POST['csrf_token']: raise ValueError('CSRF token did not match') docs/narr/traversal.rst
@@ -83,7 +83,7 @@ The combination of the context resource and the :term:`view name` found via traversal is used later in the same request by the :term:`view lookup` subsystem to find a :term:`view callable`. How :app:`Pyramid` performs view lookup is explained within the :ref:`views_chapter` performs view lookup is explained within the :ref:`view_config_chapter` chapter. .. index:: @@ -217,13 +217,14 @@ works, and some example traversal scenarios that might help you understand how the algorithm operates against a specific resource tree. We'll also talk a bit about :term:`view lookup`. The :ref:`views_chapter` chapter discusses :term:`view lookup` in detail, and it is the canonical source for information about views. Technically, :term:`view lookup` is a :app:`Pyramid` subsystem that is separated from traversal entirely. However, we'll describe the fundamental behavior of view lookup in the examples in the next few sections to give you an idea of how traversal and view lookup cooperate, because they are almost always used together. We'll also talk a bit about :term:`view lookup`. The :ref:`view_config_chapter` chapter discusses :term:`view lookup` in detail, and it is the canonical source for information about views. Technically, :term:`view lookup` is a :app:`Pyramid` subsystem that is separated from traversal entirely. However, we'll describe the fundamental behavior of view lookup in the examples in the next few sections to give you an idea of how traversal and view lookup cooperate, because they are almost always used together. .. index:: single: view name @@ -461,7 +462,7 @@ A tutorial showing how :term:`traversal` can be used within a :app:`Pyramid` application exists in :ref:`bfg_wiki_tutorial`. See the :ref:`views_chapter` chapter for detailed information about See the :ref:`view_config_chapter` chapter for detailed information about :term:`view lookup`. The :mod:`pyramid.traversal` module contains API functions that deal with docs/narr/urldispatch.rst
@@ -26,7 +26,7 @@ :term:`request` and returns a :term:`response` object. Where appropriate, we will describe how view lookup interacts with :term:`resource location`. The :ref:`views_chapter` chapter describes :term:`resource location`. The :ref:`view_config_chapter` chapter describes the details of :term:`view lookup`. High-Level Operational Overview @@ -95,7 +95,7 @@ When a route configuration declaration names a ``view`` attribute, the value of the attribute will reference a :term:`view callable`. This view callable will be invoked when the route matches. A view callable, as described in :ref:`views_chapter`, is developer-supplied code that "does stuff" as the :ref:`view_chapter`, is developer-supplied code that "does stuff" as the result of a request. For more information about how to create view callables, see :ref:`views_chapter`. @@ -865,7 +865,8 @@ The view has access to the matchdict directly via the request, and can access variables within it that match keys present as a result of the route pattern. See :ref:`views_chapter` for more information about views. See :ref:`views_chapter`, and :ref:`view_config_chapter` for more information about views. Example 2 ~~~~~~~~~ docs/narr/viewconfig.rst
New file @@ -0,0 +1,986 @@ .. _view_config_chapter: .. _view_configuration: View Configuration ================== .. index:: single: view lookup :term:`View configuration` controls how :term:`view lookup` operates in your application. In earlier chapters, you have been exposed to a few simple view configuration declarations without much explanation. In this chapter we will explore the subject in detail. .. _view_lookup: View Lookup and Invocation -------------------------- :term:`View lookup` is the :app:`Pyramid` subsystem responsible for finding an invoking a :term:`view callable`. The view lookup subsystem is passed a :term:`context` and a :term:`request` object. :term:`View configuration` information stored within in the :term:`application registry` is compared against the context and request by the view lookup subsystem in order to find the "best" view callable for the set of circumstances implied by the context and request. :term:`View predicate` attributes are an important part of view configuration that enables the :term:`View lookup` subsystem to find and invoke the appropriate view. Predicate attributes can be thought of like "narrowers". In general, the greater number of predicate attributes possessed by a view's configuration, the more specific the circumstances need to be before the registered view callable will be invoked. Mapping a Resource or URL Pattern to a View Callable ---------------------------------------------------- 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 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 the :term:`context` resource and the :term:`request`. View configuration is performed in one of these ways: - by running a :term:`scan` against application source code which has a :class:`pyramid.view.view_config` decorator attached to a Python object as per :class:`pyramid.view.view_config` and :ref:`mapping_views_using_a_decorator_section`. - by using the :meth:`pyramid.config.Configurator.add_view` method as per :meth:`pyramid.config.Configurator.add_view` and :ref:`mapping_views_using_imperative_config_section`. - By specifying a view within a :term:`route configuration`. View configuration via a route configuration is performed by using the :meth:`pyramid.config.Configurator.add_route` method, passing a ``view`` argument specifying a view callable. - by using the :meth:`pyramid.config.Configurator.add_handler` against a :term:`view handler` class (useful only for :term:`URL dispatch` applications). .. note:: You can also add view configuration by adding a ``<view>``, ``<route>`` or ``<handler>`` declaration to :term:`ZCML` used by your application as per :ref:`mapping_views_using_zcml_section`, :ref:`view_directive`, :ref:`route_directive` or :ref:`handler_directive`. .. _view_configuration_parameters: View Configuration Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ All forms of view configuration accept the same general types of arguments. Many arguments supplied during view configuration are :term:`view predicate` arguments. View predicate arguments used during view configuration are used to narrow the set of circumstances in which :term:`view lookup` will find a particular view callable. In general, the fewer number of predicates which are supplied to a particular view configuration, the more likely it is that the associated view callable will be invoked. The greater the number supplied, the less likely. A view with five predicates will always be found and evaluated before a view with two, for example. All predicates must match for the associated view to be called. This does not mean however, that :app:`Pyramid` "stops looking" when it finds a view registration with predicates that don't match. If one set of view predicates does not match, the "next most specific" view (if any) is consulted for predicates, and so on, until a 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 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 the default notfound view. Some view configuration arguments are non-predicate arguments. These tend to modify the response of the view callable or prevent the view callable from being invoked due to an authorization policy. The presence of non-predicate arguments in a view configuration does not narrow the circumstances in which the view callable will be invoked. Non-Predicate Arguments +++++++++++++++++++++++ ``permission`` The name of a :term:`permission` that the user must possess in order to invoke the :term:`view callable`. See :ref:`view_security_section` for more information about view security and permissions. If ``permission`` is not supplied, no permission is registered for this view (it's accessible by any caller). ``attr`` The view machinery defaults to using the ``__call__`` method of the :term:`view callable` (or the function itself, if the view callable is a function) to obtain a response. The ``attr`` value allows you to vary the method attribute used to obtain the response. For example, if your view was a class, and the class has a method named ``index`` and you wanted to use this method instead of the class' ``__call__`` method to return the response, you'd say ``attr="index"`` in the view configuration for the view. This is most useful when the view definition is a class. If ``attr`` is not supplied, ``None`` is used (implying the function itself if the view is a function, or the ``__call__`` callable attribute if the view is a class). ``renderer`` Denotes the :term:`renderer` implementation which will be used to construct a :term:`response` from the associated view callable's return value. (see also :ref:`renderers_chapter`). This is either a single string term (e.g. ``json``) or a string implying a path or :term:`asset specification` (e.g. ``templates/views.pt``) naming a :term:`renderer` implementation. If the ``renderer`` value does not contain a dot (``.``), the specified string will be used to look up a renderer implementation, and that renderer implementation will be used to construct a response from the view return value. If the ``renderer`` value contains a dot (``.``), the specified term will be treated as a path, and the filename extension of the last element in the path will be used to look up the renderer implementation, which will be passed the full path. When the renderer is a path, although a path is usually just a simple relative pathname (e.g. ``templates/foo.pt``, implying that a template named "foo.pt" is in the "templates" directory relative to the directory of the current :term:`package`), a path can be absolute, starting with a slash on UNIX or a drive letter prefix on Windows. The path can alternately be a :term:`asset specification` in the form ``some.dotted.package_name:relative/path``, making it possible to address template assets which live in a separate package. The ``renderer`` attribute is optional. If it is not defined, the "null" renderer is assumed (no rendering is performed and the value is passed back to the upstream :app:`Pyramid` machinery unmolested). Note that if the view callable itself returns a :term:`response` (see :ref:`the_response`), the specified renderer implementation is never called. ``wrapper`` The :term:`view name` of a different :term:`view configuration` which will receive the response body of this view as the ``request.wrapped_body`` attribute of its own :term:`request`, and the :term:`response` returned by this view as the ``request.wrapped_response`` attribute of its own request. Using a wrapper makes it possible to "chain" views together to form a composite response. The response of the outermost wrapper view will be returned to the user. The wrapper view will be found as any view is found: see :ref:`view_lookup`. The "best" wrapper view will be found based on the lookup ordering: "under the hood" this wrapper view is looked up via ``pyramid.view.render_view_to_response(context, request, 'wrapper_viewname')``. The context and request of a wrapper view is the same context and request of the inner view. If ``wrapper`` is not supplied, no wrapper view is used. ``decorator`` A :term:`dotted Python name` to function (or the function itself) which will be used to decorate the registered :term:`view callable`. The decorator function will be called with the view callable as a single argument. The view callable it is passed will accept ``(context, request)``. The decorator must return a replacement view callable which also accepts ``(context, request)``. ``mapper`` A Python object or :term:`dotted Python name` which refers to a :term:`view mapper`, or ``None``. By default it is ``None``, which indicates that the view should use the default view mapper. This plug-point is useful for Pyramid extension developers, but it's not very useful for 'civilians' who are just developing stock Pyramid applications. Pay no attention to the man behind the curtain. 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. If ``name`` is not supplied, the empty string is used (implying the default view). ``context`` An object representing a Python class that the :term:`context` resource must be an instance of *or* the :term:`interface` that the :term:`context` resource must provide in order for this view to be found and called. This predicate is true when the :term:`context` resource is an instance of the represented class or if the :term:`context` resource provides the represented interface; it is otherwise false. If ``context`` is not supplied, the value ``None``, which matches any resource, is used. ``route_name`` If ``route_name`` is supplied, the view callable will be invoked only when the named route has matched. 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`` 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 if no other route was matched. This is when the request/context pair found via :term:`resource location` does not indicate it matched any configured route. ``request_type`` This value should be an :term:`interface` that the :term:`request` must provide in order for this view to be found and called. If ``request_type`` is not supplied, the value ``None`` is used, implying any request type. *This is an advanced feature, not often used by "civilians"*. ``request_method`` This value can either be one of the strings ``GET``, ``POST``, ``PUT``, ``DELETE``, or ``HEAD`` representing an HTTP ``REQUEST_METHOD``. A view declaration with this argument ensures that the view will only be called when the request's ``method`` attribute (aka the ``REQUEST_METHOD`` of the WSGI environment) string matches the supplied value. If ``request_method`` is not supplied, the view will be invoked regardless of the ``REQUEST_METHOD`` of the :term:`WSGI` environment. ``request_param`` This value can be any string. A view declaration with this argument ensures that the view will only be called when the :term:`request` has a key in the ``request.params`` dictionary (an HTTP ``GET`` or ``POST`` variable) that has a name which matches the supplied value. If the value supplied has a ``=`` sign in it, e.g. ``request_params="foo=123"``, then the key (``foo``) must both exist in the ``request.params`` dictionary, *and* the value must match the right hand side of the expression (``123``) for the view to "match" the current request. If ``request_param`` is not supplied, the view will be invoked without consideration of keys and values in the ``request.params`` dictionary. ``containment`` This value should be a reference to a Python class or :term:`interface` that a parent object in the context resource's :term:`lineage` must provide in order for this view to be found and called. The resources in your resource tree 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 invoke the view callable. See :ref:`location_aware` for more information about location-awareness. ``xhr`` This value should be either ``True`` or ``False``. If this value is specified and is ``True``, the :term:`WSGI` environment must possess an ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header that has the value ``XMLHttpRequest`` for the associated view callable to be found and called. This is useful for detecting AJAX requests issued from jQuery, Prototype and other Javascript libraries. If ``xhr`` is not specified, the ``HTTP_X_REQUESTED_WITH`` HTTP header is not taken into consideration when deciding whether or not to invoke the associated view callable. ``accept`` The value of this argument represents a match query for one or more mimetypes in the ``Accept`` HTTP request header. If this value is specified, it must be in one of the following forms: a mimetype match token in the form ``text/plain``, a wildcard mimetype match token in the form ``text/*`` or a match-all wildcard mimetype match token in the form ``*/*``. If any of the forms matches the ``Accept`` header of the request, this predicate will be true. If ``accept`` is not specified, the ``HTTP_ACCEPT`` HTTP header is not taken into consideration when deciding whether or not to invoke the associated view callable. ``header`` This value represents an HTTP header name or a header name/value pair. If ``header`` is specified, it must be a header name or a ``headername:headervalue`` pair. If ``header`` is specified without a value (a bare header name only, e.g. ``If-Modified-Since``), the view will only be invoked if the HTTP header exists with any value in the request. If ``header`` is specified, and possesses a name/value pair (e.g. ``User-Agent:Mozilla/.*``), the view will only be invoked if the HTTP header exists *and* the HTTP header matches the value requested. When the ``headervalue`` contains a ``:`` (colon), it will be considered a name/value pair (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). The value portion should be a regular expression. Whether or not the value represents a header name or a header name/value pair, the case of the header name is not significant. If ``header`` is not specified, the composition, presence or absence of HTTP headers is not taken into consideration when deciding whether or not to invoke the associated view callable. ``path_info`` This value represents a regular expression pattern that will be tested against the ``PATH_INFO`` WSGI environment variable to decide whether or not to call the associated view callable. If the regex matches, this predicate will be ``True``. If ``path_info`` is not specified, the WSGI ``PATH_INFO`` is not taken into consideration when deciding whether or not to invoke the associated view callable. ``custom_predicates`` If ``custom_predicates`` is specified, it must be a sequence of references to custom predicate callables. Use custom predicates when no set of predefined predicates do what you need. Custom predicates can be combined with predefined predicates as necessary. Each custom predicate callable should accept two arguments: ``context`` and ``request`` and should return either ``True`` or ``False`` after doing arbitrary evaluation of the context resource and/or the request. If all callables return ``True``, the associated view callable will be considered viable for a given request. If ``custom_predicates`` is not specified, no custom predicates are used. .. index:: single: view_config decorator .. _mapping_views_using_a_decorator_section: View Configuration Using the ``@view_config`` Decorator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For better locality of reference, you may use the :class:`pyramid.view.view_config` decorator to associate your view functions with URLs instead of using :term:`ZCML` or imperative configuration for the same purpose. .. warning:: Using this feature tends to slows down application startup slightly, as more work is performed at application startup to scan for view declarations. Usage of the ``view_config`` decorator is a form of :term:`declarative configuration`, like ZCML, but in decorator form. :class:`pyramid.view.view_config` can be used to associate :term:`view configuration` information -- as done via the equivalent imperative code or ZCML -- with a function that acts as a :app:`Pyramid` view callable. All arguments to the :meth:`pyramid.config.Configurator.add_view` method (save for the ``view`` argument) are available in decorator form and mean precisely the same thing. An example of the :class:`pyramid.view.view_config` decorator might reside in a :app:`Pyramid` application module ``views.py``: .. ignore-next-block .. code-block:: python :linenos: from resources import MyResource from pyramid.view import view_config from pyramid.response import Response @view_config(name='my_view', request_method='POST', context=MyResource, permission='read') def my_view(request): return Response('OK') Using this decorator as above replaces the need to add this imperative configuration stanza: .. ignore-next-block .. code-block:: python :linenos: config.add_view('.views.my_view', name='my_view', request_method='POST', context=MyResource, permission='read') All arguments to ``view_config`` may be omitted. For example: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import view_config @view_config() def my_view(request): """ My view """ return Response() 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 resource type, using no permission, registered against 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. 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`: .. code-block:: python :linenos: # config is assumed to be an instance of the # pyramid.config.Configurator class config.scan() .. note:: See :ref:`zcml_scanning` for information about how to invoke a scan via ZCML (if you're not using imperative configuration). Please see :ref:`decorations_and_code_scanning` for detailed information about what happens when code is scanned for configuration declarations resulting from use of decorators like :class:`pyramid.view.view_config`. See :ref:`configuration_module` for additional API arguments to the :meth:`pyramid.config.Configurator.scan` method. For example, the method allows you to supply a ``package`` argument to better control exactly *which* code will be scanned. ``@view_config`` Placement ++++++++++++++++++++++++++ A :class:`pyramid.view.view_config` decorator can be placed in various points in your application. If your view callable is a function, it may be used as a function decorator: .. code-block:: python :linenos: from pyramid.view import view_config from pyramid.response import Response @view_config(name='edit') def edit(request): return Response('edited!') If your view callable is a class, the decorator can also be used as a class decorator in Python 2.6 and better (Python 2.5 and below do not support class decorators). All the arguments to the decorator are the same when applied against a class as when they are applied against a function. For example: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import view_config @view_config() class MyView(object): def __init__(self, request): self.request = request def __call__(self): return Response('hello') You can use the :class:`pyramid.view.view_config` decorator as a simple callable to manually decorate classes in Python 2.5 and below without the decorator syntactic sugar, if you wish: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import view_config class MyView(object): def __init__(self, request): self.request = request def __call__(self): return Response('hello') my_view = view_config()(MyView) More than one :class:`pyramid.view.view_config` decorator can be stacked on top of any number of others. Each decorator creates a separate view registration. For example: .. code-block:: python :linenos: from pyramid.view import view_config from pyramid.response import Response @view_config(name='edit') @view_config(name='change') def edit(request): return Response('edited!') This registers the same view under two different names. The decorator can also be used against class methods: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import view_config class MyView(object): def __init__(self, request): self.request = request @view_config(name='hello') def amethod(self): return Response('hello') 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``. The method which is decorated must return a :term:`response`. Using the decorator against a particular method of a class is equivalent to using the ``attr`` parameter in a decorator attached to the class itself. For example, the above registration implied by the decorator being used against the ``amethod`` method could be spelled equivalently as the below: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import view_config @view_config(attr='amethod', name='hello') class MyView(object): def __init__(self, request): self.request = request def amethod(self): return Response('hello') .. index:: single: add_view .. _mapping_views_using_imperative_config_section: View Registration Using :meth:`~pyramid.config.Configurator.add_view` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The :meth:`pyramid.config.Configurator.add_view` method within :ref:`configuration_module` is used to configure a view imperatively. The arguments to this method are very similar to the arguments that you provide to the ``@view_config`` decorator. For example: .. code-block:: python :linenos: from pyramid.response import Response def hello_world(request): return Response('hello!') # config is assumed to be an instance of the # pyramid.config.Configurator class config.add_view(hello_world, name='hello.html') The first argument, ``view``, is required. It must either be a Python object which is the view itself or a :term:`dotted Python name` to such an object. All other arguments are optional. See :meth:`pyramid.config.Configurator.add_view` for more information. .. _using_add_handler: Handler Registration Using :meth:`~pyramid.config.Configurator.add_handler` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :app:`Pyramid` provides the special concept of a :term:`view handler`. View handlers are view classes that implement a number of methods, each of which is a :term:`view callable` as a convenience for :term:`URL dispatch` users. .. note:: View handlers are *not* useful when using :term:`traversal`, only when using :term:`url dispatch`. Using a view handler instead of a plain function or class :term:`view callable` makes it unnecessary to call :meth:`pyramid.config.Configurator.add_route` (and/or :meth:`pyramid.config.Configurator.add_view`) "by hand" multiple times, making it more pleasant to register a collection of views as a single class when using :term:`url dispatch`. The view handler machinery also introduces the concept of an ``action``, which is used as a :term:`view predicate` to control which method of the handler is called. The method name is the default *action name* of a handler view callable. 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 "plain" view class. Its ``__init__`` is called with a request object (see :ref:`class_as_view`). It implements methods, each of which is a :term:`view callable`. When a request enters the system which corresponds with an *action* related to one of its view callable methods, this method is called, and it is expected to return a response. Here's an example view handler class: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import action class Hello(object): def __init__(self, request): self.request = request def index(self): return Response('Hello world!') @action(renderer="mytemplate.mak") def bye(self): return {} The :class:`pyramid.view.action` decorator is used to fine-tune the view parameters for each potential view callable which is a method of the handler. Handlers are added to application configuration via the :meth:`pyramid.config.Configurator.add_handler` API. The :meth:`~pyramid.config.Configurator.add_handler` method will scan a :term:`view handler` class and automatically set up view configurations for its methods that represent "auto-exposed" view callable, or those that were decorated explicitly 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. .. code-block:: python :linenos: from myapp.handlers import Hello config.add_handler('hello', '/hello/{action}', handler=Hello) This example will result in a route being added for the pattern ``/hello/{action}``, and each method of the ``Hello`` class will then be examined to see if it should be registered as a potential view callable when the ``/hello/{action}`` pattern matches. The value of ``{action}`` in the route pattern will be used to determine which view should be called, and each view in the class will be setup with a view predicate that requires a specific ``action`` name. By default, the action name for a method of a handler is the method name. If the URL was ``/hello/index``, the above example pattern would match, and, by default, the ``index`` method of the ``Hello`` class would be called. Alternatively, the action can be declared specifically for a URL to be registered for a *specific* ``action`` name: .. code-block:: python :linenos: from myapp.handlers import Hello config.add_handler('hello_index', '/hello/index', 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. 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. When calling :meth:`~pyramid.config.Configurator.add_handler`, an ``action`` is required in either the route pattern or as a keyword argument, but **cannot appear in both places**. A ``handler`` argument must also be supplied, which can be either a :term:`asset specification` or a Python reference to the handler class. Additional keyword arguments are passed directly through to :meth:`pyramid.config.Configurator.add_route`. For example: .. code-block:: python :linenos: config.add_handler('hello', '/hello/{action}', handler='mypackage.handlers.MyHandler') Multiple :meth:`~pyramid.config.Configurator.add_handler` calls can specify the same handler, to register specific route names for different handler/action combinations. For example: .. code-block:: python :linenos: config.add_handler('hello_index', '/hello/index', handler=Hello, action='index') config.add_handler('bye_index', '/hello/bye', handler=Hello, action='bye') .. note:: Handler configuration may also be added to the system via :term:`ZCML` (see :ref:`zcml_handler_configuration`). View Setup in the Handler Class +++++++++++++++++++++++++++++++ A handler class can have a single class level attribute called ``__autoexpose__`` which should be a regular expression or the value ``None``. It's used to determine which method names will result in additional view configurations being registered. When :meth:`~pyramid.config.Configurator.add_handler` runs, every method in the handler class will be searched and a view registered if the method name matches the ``__autoexpose__`` regular expression, or if the method was decorated with :class:`~pyramid.view.action`. Every method in the handler class that has a name meeting the ``__autoexpose__`` regular expression will have a view registered for an ``action`` name corresponding to the method name. This functionality can be disabled by setting the ``__autoexpose__`` attribute to ``None``: .. code-block:: python :linenos: from pyramid.view import action class Hello(object): __autoexpose__ = None def __init__(self, request): self.request = request @action() def index(self): return Response('Hello world!') @action(renderer="mytemplate.mak") def bye(self): return {} With auto-expose effectively disabled, no views will be registered for a method unless it is specifically decorated with :class:`~pyramid.view.action`. Action Decorators in a Handler ++++++++++++++++++++++++++++++ The :class:`~pyramid.view.action` decorator registers view configuration information on the handler method, which is used by :meth:`~pyramid.config.Configurator.add_handler` to setup the view configuration. All keyword arguments are recorded, and passed to :meth:`~pyramid.config.Configurator.add_view`. Any valid keyword arguments for :meth:`~pyramid.config.Configurator.add_view` can thus be used with the :class:`~pyramid.view.action` decorator to further restrict when the view will be called. One important difference is that a handler method can respond to an ``action`` name that is different from the method name by passing in a ``name`` argument. Example: .. code-block:: python :linenos: from pyramid.view import action class Hello(object): def __init__(self, request): self.request = request @action(name='index', renderer='created.mak', request_method='POST') def create(self): return {} @action(renderer="view_all.mak", request_method='GET') def index(self): return {} This will register two views that require the ``action`` to be ``index``, with the additional view predicate requiring a specific request method. 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: .. code-block:: python :linenos: from pyramid.view import action class Hello(object): def __init__(self, request): self.request = request @action(name='home', renderer='home.mak') @action(name='about', renderer='about.mak') def show_template(self): # prep some template vars return {} # in the config config.add_handler('hello', '/hello/{action}', handler=Hello) With this configuration, the url ``/hello/home`` will find a view configuration that results in calling the ``show_template`` method, then rendering the template with ``home.mak``, and the url ``/hello/about`` will call the same method and render the ``about.mak`` template. .. index:: single: resource interfaces .. _using_resource_interfaces: Using Resource Interfaces In View Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Instead of registering your views with a ``context`` that names a Python resource *class*, you can optionally register a view callable with a ``context`` which is an :term:`interface`. An interface can be attached arbitrarily to any resource object. View lookup treats context interfaces specially, and therefore the identity of a resource can be divorced from that of the class which implements it. As a result, associating a view with an interface can provide more flexibility for sharing a single view between two or more different implementations of a resource type. For example, if two resource objects of different Python class types share the same interface, you can use the same view configuration to specify both of them as a ``context``. In order to make use of interfaces in your application during view dispatch, you must create an interface and mark up your resource classes or instances with interface declarations that refer to this interface. To attach an interface to a resource *class*, you define the interface and use the :func:`zope.interface.implements` function to associate the interface with the class. .. code-block:: python :linenos: from zope.interface import Interface from zope.interface import implements class IHello(Interface): """ A marker interface """ class Hello(object): implements(IHello) To attach an interface to a resource *instance*, you define the interface and use the :func:`zope.interface.alsoProvides` function to associate the interface with the instance. This function mutates the instance in such a way that the interface is attached to it. .. code-block:: python :linenos: from zope.interface import Interface from zope.interface import alsoProvides class IHello(Interface): """ A marker interface """ class Hello(object): pass def make_hello(): hello = Hello() alsoProvides(hello, IHello) return hello Regardless of how you associate an interface, with a resource instance, or a resource 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 "resources.py", the interface declaration below will associate the ``mypackage.views.hello_world`` view with resources that implement, or provide, this interface. .. code-block:: python :linenos: # config is an instance of pyramid.config.Configurator config.add_view('mypackage.views.hello_world', name='hello.html', context='mypackage.resources.IHello') Any time a resource 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, in cases where a view is registered against a resource class, and a view is also registered against an interface that the resource class implements, an ambiguity arises. Views registered for the resource class take precedence over any views registered for any interface the resource class implements. Thus, if one view configuration names a ``context`` of both the class type of a resource, and another view configuration names a ``context`` of interface implemented by the resource's class, and both view configurations are otherwise identical, the view registered for the context's class will "win". For more information about defining resources with interfaces for use within view configuration, see :ref:`resources_which_implement_interfaces`. .. index:: single: view security pair: security; view .. _view_security_section: Configuring View Security ~~~~~~~~~~~~~~~~~~~~~~~~~ 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` resource 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`: .. code-block:: python :linenos: # config is an instance of pyramid.config.Configurator config.add_view('myproject.views.add_entry', name='add.html', context='myproject.resources.IBlog', permission='add') 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: debugging not found errors single: not found error (debugging) .. _debug_notfound_section: :exc:`NotFound` Errors ~~~~~~~~~~~~~~~~~~~~~~ It's useful to be able to debug :exc:`NotFound` error responses when they occur unexpectedly due to an application registry misconfiguration. To debug these errors, use the ``PYRAMID_DEBUG_NOTFOUND`` environment variable or the ``debug_notfound`` 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. docs/narr/views.rst
@@ -17,11 +17,12 @@ that implements a view *callable*, and the process of view *lookup*. The :ref:`urldispatch_chapter`, and :ref:`traversal_chapter` describes how, using information from the :term:`request`, a :term:`context` resource is computed. But the context resource itself isn't very useful without an associated :term:`view callable`. A view callable returns a response to a user, often using the context resource to do so. The :ref:`urldispatch_chapter`, and :ref:`traversal_chapter` chapters describes how, using information from the :term:`request`, a :term:`context` resource is computed. But the context resource itself isn't very useful without an associated :term:`view callable`. A view callable returns a response to a user, often using the context resource to do so. The job of actually locating and invoking the "best" :term:`view callable` is the job of the :term:`view lookup` subsystem. The view lookup subsystem @@ -30,31 +31,34 @@ the developer to choose the most appropriate view callable for a specific set of circumstances. This chapter provides documentation detailing the process of creating view callables, documentation about performing view configuration, and a detailed explanation of view lookup. This chapter describes how view callables work. In the :ref:`view_config_chapter` chapter, there are details about performing view configuration, and a detailed explanation of view lookup. View Callables -------------- No matter how a view callable is eventually found, all view callables used by :app:`Pyramid` must be constructed in the same way, and must return the same kind of return value. View callables are, at the risk of sounding obvious, callable Python objects. Specifically, view callables can be functions, classes, or instances that implement an ``__call__`` method (making the instance callable). Most view callables accept a single argument named ``request``. This argument 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. View callables must, at a minimum, accept a single argument named ``request``. This argument represents a :app:`Pyramid` :term:`Request` object. A request object encapsulates a WSGI environment provided to :app:`Pyramid` by the upstream :term:`WSGI` server. As you might expect, the request object contains everything your application needs to know about the specific HTTP request being made. In general, a view callable must return a :mod:`Pyramid` :term:`Response` object. .. note:: The above statement, though it sounds definitive, isn't always true. See :ref:`renderers_chapter` for information related to using a :term:`renderer` to convert a non-Response view callable return value into a Response object. View callables can be functions, instances, or classes. A view callable's ultimate responsibility is to create a :mod:`Pyramid` :term:`Response` object. This can be done by creating the response object in the view callable code and returning it directly, as we will be doing in this chapter. However, if a view callable does not return a response itself, it can be configured to use a :term:`renderer` that converts its return value into a :term:`Response` object. Using renderers is the common way that templates are used with view callables to generate markup. See the :ref:`renderers_chapter` chapter for details. .. index:: single: view calling convention @@ -63,7 +67,7 @@ .. _function_as_view: Defining a View Callable as a Function ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -------------------------------------- One of the easiest way to define a view callable is to create a function that accepts a single argument named ``request``, and which returns a @@ -85,7 +89,7 @@ .. _class_as_view: Defining a View Callable as a Class ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ----------------------------------- A view callable may also be represented by a Python class instead of a function. When a view callable is a class, the calling semantics are @@ -135,7 +139,7 @@ .. _request_and_context_view_definitions: Alternate View Callable Argument/Calling Conventions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ---------------------------------------------------- Usually, view callables are defined to accept only a single argument: ``request``. However, view callables may alternately be defined as classes, @@ -210,7 +214,7 @@ .. _the_response: View Callable Responses ~~~~~~~~~~~~~~~~~~~~~~~ ----------------------- A view callable may always return an object that implements the :app:`Pyramid` :term:`Response` interface. The easiest way to return something that @@ -256,7 +260,7 @@ .. _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. @@ -295,7 +299,7 @@ .. _special_exceptions_in_callables: Using Special Exceptions In View Callables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ------------------------------------------ Usually when a Python exception is raised within a view callable, :app:`Pyramid` allows the exception to propagate all the way out to the @@ -325,7 +329,7 @@ .. _exception_views: Exception Views ~~~~~~~~~~~~~~~~ --------------- The machinery which allows the special :exc:`pyramid.exceptions.NotFound` and :exc:`pyramid.exceptions.Forbidden` exceptions to be caught by specialized @@ -403,1106 +407,4 @@ 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 single: forms, views, and unicode single: views, forms, and unicode Handling Form Submissions in View Callables (Unicode and Character Set Issues) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Most web applications need to accept form submissions from web browsers and various other clients. In :app:`Pyramid`, form submission handling logic is always part of a :term:`view`. For a general overview of how to handle form submission data using the :term:`WebOb` API, see :ref:`webob_chapter` and `"Query and POST variables" within the WebOb documentation <http://pythonpaste.org/webob/reference.html#query-post-variables>`_. :app:`Pyramid` defers to WebOb for its request and response 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. 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 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). .. 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 transit 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: .. code-block:: xml :linenos: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> </head> <form method="POST" action="myview"> <div> <input type="text" name="firstname"/> </div> <div> <input type="text" name="lastname"/> </div> <input type="submit" value="Submit"/> </form> </html> The ``myview`` view code in the :app:`Pyramid` application *must* expect that the values returned by ``request.params`` will be of type ``unicode``, as opposed to type ``str``. The following will work to accept a form post from the above form: .. code-block:: python :linenos: def myview(request): firstname = request.params['firstname'] lastname = request.params['lastname'] But the following ``myview`` view code *may not* work, as it tries to decode already-decoded (``unicode``) values obtained from ``request.params``: .. code-block:: python :linenos: def myview(request): # the .decode('utf-8') will break below if there are any high-order # characters in the firstname or lastname 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 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 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``, ``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 (byte) strings. .. index:: single: view configuration .. _view_configuration: View Configuration: Mapping a Resource or URL Pattern to a View Callable ------------------------------------------------------------------------ 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 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 the :term:`context` resource and the :term:`request`. View configuration is performed in one of these ways: - by running a :term:`scan` against application source code which has a :class:`pyramid.view.view_config` decorator attached to a Python object as per :class:`pyramid.view.view_config` and :ref:`mapping_views_using_a_decorator_section`. - by using the :meth:`pyramid.config.Configurator.add_view` method as per :meth:`pyramid.config.Configurator.add_view` and :ref:`mapping_views_using_imperative_config_section`. - By specifying a view within a :term:`route configuration`. View configuration via a route configuration is performed by using the :meth:`pyramid.config.Configurator.add_route` method, passing a ``view`` argument specifying a view callable. - by using the :meth:`pyramid.config.Configurator.add_handler` against a :term:`view handler` class (useful only for :term:`URL dispatch` applications). .. note:: You can also add view configuration by adding a ``<view>``, ``<route>`` or ``<handler>`` declaration to :term:`ZCML` used by your application as per :ref:`mapping_views_using_zcml_section`, :ref:`view_directive`, :ref:`route_directive` or :ref:`handler_directive`. .. _view_configuration_parameters: View Configuration Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ All forms of view configuration accept the same general types of arguments. Many arguments supplied during view configuration are :term:`view predicate` arguments. View predicate arguments used during view configuration are used to narrow the set of circumstances in which :mod:`view lookup` will find a particular view callable. In general, the fewer number of predicates which are supplied to a particular view configuration, the more likely it is that the associated view callable will be invoked. The greater the number supplied, the less likely. Some view configuration arguments are non-predicate arguments. These tend to modify the response of the view callable or prevent the view callable from being invoked due to an authorization policy. The presence of non-predicate arguments in a view configuration does not narrow the circumstances in which the view callable will be invoked. Non-Predicate Arguments +++++++++++++++++++++++ ``permission`` The name of a :term:`permission` that the user must possess in order to invoke the :term:`view callable`. See :ref:`view_security_section` for more information about view security and permissions. If ``permission`` is not supplied, no permission is registered for this view (it's accessible by any caller). ``attr`` The view machinery defaults to using the ``__call__`` method of the :term:`view callable` (or the function itself, if the view callable is a function) to obtain a response. The ``attr`` value allows you to vary the method attribute used to obtain the response. For example, if your view was a class, and the class has a method named ``index`` and you wanted to use this method instead of the class' ``__call__`` method to return the response, you'd say ``attr="index"`` in the view configuration for the view. This is most useful when the view definition is a class. If ``attr`` is not supplied, ``None`` is used (implying the function itself if the view is a function, or the ``__call__`` callable attribute if the view is a class). ``renderer`` Denotes the :term:`renderer` implementation which will be used to construct a :term:`response` from the associated view callable's return value. (see also :ref:`renderers_chapter`). This is either a single string term (e.g. ``json``) or a string implying a path or :term:`asset specification` (e.g. ``templates/views.pt``) naming a :term:`renderer` implementation. If the ``renderer`` value does not contain a dot (``.``), the specified string will be used to look up a renderer implementation, and that renderer implementation will be used to construct a response from the view return value. If the ``renderer`` value contains a dot (``.``), the specified term will be treated as a path, and the filename extension of the last element in the path will be used to look up the renderer implementation, which will be passed the full path. When the renderer is a path, although a path is usually just a simple relative pathname (e.g. ``templates/foo.pt``, implying that a template named "foo.pt" is in the "templates" directory relative to the directory of the current :term:`package`), a path can be absolute, starting with a slash on UNIX or a drive letter prefix on Windows. The path can alternately be a :term:`asset specification` in the form ``some.dotted.package_name:relative/path``, making it possible to address template assets which live in a separate package. The ``renderer`` attribute is optional. If it is not defined, the "null" renderer is assumed (no rendering is performed and the value is passed back to the upstream :app:`Pyramid` machinery unmolested). Note that if the view callable itself returns a :term:`response` (see :ref:`the_response`), the specified renderer implementation is never called. ``wrapper`` The :term:`view name` of a different :term:`view configuration` which will receive the response body of this view as the ``request.wrapped_body`` attribute of its own :term:`request`, and the :term:`response` returned by this view as the ``request.wrapped_response`` attribute of its own request. Using a wrapper makes it possible to "chain" views together to form a composite response. The response of the outermost wrapper view will be returned to the user. The wrapper view will be found as any view is found: see :ref:`view_lookup`. The "best" wrapper view will be found based on the lookup ordering: "under the hood" this wrapper view is looked up via ``pyramid.view.render_view_to_response(context, request, 'wrapper_viewname')``. The context and request of a wrapper view is the same context and request of the inner view. If ``wrapper`` is not supplied, no wrapper view is used. ``decorator`` A :term:`dotted Python name` to function (or the function itself) which will be used to decorate the registered :term:`view callable`. The decorator function will be called with the view callable as a single argument. The view callable it is passed will accept ``(context, request)``. The decorator must return a replacement view callable which also accepts ``(context, request)``. ``mapper`` A Python object or :term:`dotted Python name` which refers to a :term:`view mapper`, or ``None``. By default it is ``None``, which indicates that the view should use the default view mapper. This plug-point is useful for Pyramid extension developers, but it's not very useful for 'civilians' who are just developing stock Pyramid applications. Pay no attention to the man behind the curtain. 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. If ``name`` is not supplied, the empty string is used (implying the default view). ``context`` An object representing a Python class that the :term:`context` resource must be an instance of *or* the :term:`interface` that the :term:`context` resource must provide in order for this view to be found and called. This predicate is true when the :term:`context` resource is an instance of the represented class or if the :term:`context` resource provides the represented interface; it is otherwise false. If ``context`` is not supplied, the value ``None``, which matches any resource, is used. ``route_name`` If ``route_name`` is supplied, the view callable will be invoked only when the named route has matched. 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`` 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 if no other route was matched. This is when the request/context pair found via :term:`resource location` does not indicate it matched any configured route. ``request_type`` This value should be an :term:`interface` that the :term:`request` must provide in order for this view to be found and called. If ``request_type`` is not supplied, the value ``None`` is used, implying any request type. *This is an advanced feature, not often used by "civilians"*. ``request_method`` This value can either be one of the strings ``GET``, ``POST``, ``PUT``, ``DELETE``, or ``HEAD`` representing an HTTP ``REQUEST_METHOD``. A view declaration with this argument ensures that the view will only be called when the request's ``method`` attribute (aka the ``REQUEST_METHOD`` of the WSGI environment) string matches the supplied value. If ``request_method`` is not supplied, the view will be invoked regardless of the ``REQUEST_METHOD`` of the :term:`WSGI` environment. ``request_param`` This value can be any string. A view declaration with this argument ensures that the view will only be called when the :term:`request` has a key in the ``request.params`` dictionary (an HTTP ``GET`` or ``POST`` variable) that has a name which matches the supplied value. If the value supplied has a ``=`` sign in it, e.g. ``request_params="foo=123"``, then the key (``foo``) must both exist in the ``request.params`` dictionary, *and* the value must match the right hand side of the expression (``123``) for the view to "match" the current request. If ``request_param`` is not supplied, the view will be invoked without consideration of keys and values in the ``request.params`` dictionary. ``containment`` This value should be a reference to a Python class or :term:`interface` that a parent object in the context resource's :term:`lineage` must provide in order for this view to be found and called. The resources in your resource tree 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 invoke the view callable. See :ref:`location_aware` for more information about location-awareness. ``xhr`` This value should be either ``True`` or ``False``. If this value is specified and is ``True``, the :term:`WSGI` environment must possess an ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header that has the value ``XMLHttpRequest`` for the associated view callable to be found and called. This is useful for detecting AJAX requests issued from jQuery, Prototype and other Javascript libraries. If ``xhr`` is not specified, the ``HTTP_X_REQUESTED_WITH`` HTTP header is not taken into consideration when deciding whether or not to invoke the associated view callable. ``accept`` The value of this argument represents a match query for one or more mimetypes in the ``Accept`` HTTP request header. If this value is specified, it must be in one of the following forms: a mimetype match token in the form ``text/plain``, a wildcard mimetype match token in the form ``text/*`` or a match-all wildcard mimetype match token in the form ``*/*``. If any of the forms matches the ``Accept`` header of the request, this predicate will be true. If ``accept`` is not specified, the ``HTTP_ACCEPT`` HTTP header is not taken into consideration when deciding whether or not to invoke the associated view callable. ``header`` This value represents an HTTP header name or a header name/value pair. If ``header`` is specified, it must be a header name or a ``headername:headervalue`` pair. If ``header`` is specified without a value (a bare header name only, e.g. ``If-Modified-Since``), the view will only be invoked if the HTTP header exists with any value in the request. If ``header`` is specified, and possesses a name/value pair (e.g. ``User-Agent:Mozilla/.*``), the view will only be invoked if the HTTP header exists *and* the HTTP header matches the value requested. When the ``headervalue`` contains a ``:`` (colon), it will be considered a name/value pair (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). The value portion should be a regular expression. Whether or not the value represents a header name or a header name/value pair, the case of the header name is not significant. If ``header`` is not specified, the composition, presence or absence of HTTP headers is not taken into consideration when deciding whether or not to invoke the associated view callable. ``path_info`` This value represents a regular expression pattern that will be tested against the ``PATH_INFO`` WSGI environment variable to decide whether or not to call the associated view callable. If the regex matches, this predicate will be ``True``. If ``path_info`` is not specified, the WSGI ``PATH_INFO`` is not taken into consideration when deciding whether or not to invoke the associated view callable. ``custom_predicates`` If ``custom_predicates`` is specified, it must be a sequence of references to custom predicate callables. Use custom predicates when no set of predefined predicates do what you need. Custom predicates can be combined with predefined predicates as necessary. Each custom predicate callable should accept two arguments: ``context`` and ``request`` and should return either ``True`` or ``False`` after doing arbitrary evaluation of the context resource and/or the request. If all callables return ``True``, the associated view callable will be considered viable for a given request. If ``custom_predicates`` is not specified, no custom predicates are used. .. index:: single: view_config decorator .. _mapping_views_using_a_decorator_section: View Configuration Using the ``@view_config`` Decorator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For better locality of reference, you may use the :class:`pyramid.view.view_config` decorator to associate your view functions with URLs instead of using :term:`ZCML` or imperative configuration for the same purpose. .. warning:: Using this feature tends to slows down application startup slightly, as more work is performed at application startup to scan for view declarations. Usage of the ``view_config`` decorator is a form of :term:`declarative configuration`, like ZCML, but in decorator form. :class:`pyramid.view.view_config` can be used to associate :term:`view configuration` information -- as done via the equivalent imperative code or ZCML -- with a function that acts as a :app:`Pyramid` view callable. All arguments to the :meth:`pyramid.config.Configurator.add_view` method (save for the ``view`` argument) are available in decorator form and mean precisely the same thing. An example of the :class:`pyramid.view.view_config` decorator might reside in a :app:`Pyramid` application module ``views.py``: .. ignore-next-block .. code-block:: python :linenos: from resources import MyResource from pyramid.view import view_config from pyramid.response import Response @view_config(name='my_view', request_method='POST', context=MyResource, permission='read') def my_view(request): return Response('OK') Using this decorator as above replaces the need to add this imperative configuration stanza: .. ignore-next-block .. code-block:: python :linenos: config.add_view('.views.my_view', name='my_view', request_method='POST', context=MyResource, permission='read') All arguments to ``view_config`` may be omitted. For example: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import view_config @view_config() def my_view(request): """ My view """ return Response() 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 resource type, using no permission, registered against 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. 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`: .. code-block:: python :linenos: # config is assumed to be an instance of the # pyramid.config.Configurator class config.scan() .. note:: See :ref:`zcml_scanning` for information about how to invoke a scan via ZCML (if you're not using imperative configuration). Please see :ref:`decorations_and_code_scanning` for detailed information about what happens when code is scanned for configuration declarations resulting from use of decorators like :class:`pyramid.view.view_config`. See :ref:`configuration_module` for additional API arguments to the :meth:`pyramid.config.Configurator.scan` method. For example, the method allows you to supply a ``package`` argument to better control exactly *which* code will be scanned. ``@view_config`` Placement ++++++++++++++++++++++++++ A :class:`pyramid.view.view_config` decorator can be placed in various points in your application. If your view callable is a function, it may be used as a function decorator: .. code-block:: python :linenos: from pyramid.view import view_config from pyramid.response import Response @view_config(name='edit') def edit(request): return Response('edited!') If your view callable is a class, the decorator can also be used as a class decorator in Python 2.6 and better (Python 2.5 and below do not support class decorators). All the arguments to the decorator are the same when applied against a class as when they are applied against a function. For example: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import view_config @view_config() class MyView(object): def __init__(self, request): self.request = request def __call__(self): return Response('hello') You can use the :class:`pyramid.view.view_config` decorator as a simple callable to manually decorate classes in Python 2.5 and below without the decorator syntactic sugar, if you wish: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import view_config class MyView(object): def __init__(self, request): self.request = request def __call__(self): return Response('hello') my_view = view_config()(MyView) More than one :class:`pyramid.view.view_config` decorator can be stacked on top of any number of others. Each decorator creates a separate view registration. For example: .. code-block:: python :linenos: from pyramid.view import view_config from pyramid.response import Response @view_config(name='edit') @view_config(name='change') def edit(request): return Response('edited!') This registers the same view under two different names. The decorator can also be used against class methods: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import view_config class MyView(object): def __init__(self, request): self.request = request @view_config(name='hello') def amethod(self): return Response('hello') 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``. The method which is decorated must return a :term:`response`. Using the decorator against a particular method of a class is equivalent to using the ``attr`` parameter in a decorator attached to the class itself. For example, the above registration implied by the decorator being used against the ``amethod`` method could be spelled equivalently as the below: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import view_config @view_config(attr='amethod', name='hello') class MyView(object): def __init__(self, request): self.request = request def amethod(self): return Response('hello') .. index:: single: add_view .. _mapping_views_using_imperative_config_section: View Registration Using :meth:`~pyramid.config.Configurator.add_view` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The :meth:`pyramid.config.Configurator.add_view` method within :ref:`configuration_module` is used to configure a view imperatively. The arguments to this method are very similar to the arguments that you provide to the ``@view_config`` decorator. For example: .. code-block:: python :linenos: from pyramid.response import Response def hello_world(request): return Response('hello!') # config is assumed to be an instance of the # pyramid.config.Configurator class config.add_view(hello_world, name='hello.html') The first argument, ``view``, is required. It must either be a Python object which is the view itself or a :term:`dotted Python name` to such an object. All other arguments are optional. See :meth:`pyramid.config.Configurator.add_view` for more information. .. _using_add_handler: Handler Registration Using :meth:`~pyramid.config.Configurator.add_handler` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :app:`Pyramid` provides the special concept of a :term:`view handler`. View handlers are view classes that implement a number of methods, each of which is a :term:`view callable` as a convenience for :term:`URL dispatch` users. .. note:: View handlers are *not* useful when using :term:`traversal`, only when using :term:`url dispatch`. Using a view handler instead of a plain function or class :term:`view callable` makes it unnecessary to call :meth:`pyramid.config.Configurator.add_route` (and/or :meth:`pyramid.config.Configurator.add_view`) "by hand" multiple times, making it more pleasant to register a collection of views as a single class when using :term:`url dispatch`. The view handler machinery also introduces the concept of an ``action``, which is used as a :term:`view predicate` to control which method of the handler is called. The method name is the default *action name* of a handler view callable. 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 "plain" view class. Its ``__init__`` is called with a request object (see :ref:`class_as_view`). It implements methods, each of which is a :term:`view callable`. When a request enters the system which corresponds with an *action* related to one of its view callable methods, this method is called, and it is expected to return a response. Here's an example view handler class: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.view import action class Hello(object): def __init__(self, request): self.request = request def index(self): return Response('Hello world!') @action(renderer="mytemplate.mak") def bye(self): return {} The :class:`pyramid.view.action` decorator is used to fine-tune the view parameters for each potential view callable which is a method of the handler. Handlers are added to application configuration via the :meth:`pyramid.config.Configurator.add_handler` API. The :meth:`~pyramid.config.Configurator.add_handler` method will scan a :term:`view handler` class and automatically set up view configurations for its methods that represent "auto-exposed" view callable, or those that were decorated explicitly 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. .. code-block:: python :linenos: from myapp.handlers import Hello config.add_handler('hello', '/hello/{action}', handler=Hello) This example will result in a route being added for the pattern ``/hello/{action}``, and each method of the ``Hello`` class will then be examined to see if it should be registered as a potential view callable when the ``/hello/{action}`` pattern matches. The value of ``{action}`` in the route pattern will be used to determine which view should be called, and each view in the class will be setup with a view predicate that requires a specific ``action`` name. By default, the action name for a method of a handler is the method name. If the URL was ``/hello/index``, the above example pattern would match, and, by default, the ``index`` method of the ``Hello`` class would be called. Alternatively, the action can be declared specifically for a URL to be registered for a *specific* ``action`` name: .. code-block:: python :linenos: from myapp.handlers import Hello config.add_handler('hello_index', '/hello/index', 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. 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. When calling :meth:`~pyramid.config.Configurator.add_handler`, an ``action`` is required in either the route pattern or as a keyword argument, but **cannot appear in both places**. A ``handler`` argument must also be supplied, which can be either a :term:`asset specification` or a Python reference to the handler class. Additional keyword arguments are passed directly through to :meth:`pyramid.config.Configurator.add_route`. For example: .. code-block:: python :linenos: config.add_handler('hello', '/hello/{action}', handler='mypackage.handlers.MyHandler') Multiple :meth:`~pyramid.config.Configurator.add_handler` calls can specify the same handler, to register specific route names for different handler/action combinations. For example: .. code-block:: python :linenos: config.add_handler('hello_index', '/hello/index', handler=Hello, action='index') config.add_handler('bye_index', '/hello/bye', handler=Hello, action='bye') .. note:: Handler configuration may also be added to the system via :term:`ZCML` (see :ref:`zcml_handler_configuration`). View Setup in the Handler Class +++++++++++++++++++++++++++++++ A handler class can have a single class level attribute called ``__autoexpose__`` which should be a regular expression or the value ``None``. It's used to determine which method names will result in additional view configurations being registered. When :meth:`~pyramid.config.Configurator.add_handler` runs, every method in the handler class will be searched and a view registered if the method name matches the ``__autoexpose__`` regular expression, or if the method was decorated with :class:`~pyramid.view.action`. Every method in the handler class that has a name meeting the ``__autoexpose__`` regular expression will have a view registered for an ``action`` name corresponding to the method name. This functionality can be disabled by setting the ``__autoexpose__`` attribute to ``None``: .. code-block:: python :linenos: from pyramid.view import action class Hello(object): __autoexpose__ = None def __init__(self, request): self.request = request @action() def index(self): return Response('Hello world!') @action(renderer="mytemplate.mak") def bye(self): return {} With auto-expose effectively disabled, no views will be registered for a method unless it is specifically decorated with :class:`~pyramid.view.action`. Action Decorators in a Handler ++++++++++++++++++++++++++++++ The :class:`~pyramid.view.action` decorator registers view configuration information on the handler method, which is used by :meth:`~pyramid.config.Configurator.add_handler` to setup the view configuration. All keyword arguments are recorded, and passed to :meth:`~pyramid.config.Configurator.add_view`. Any valid keyword arguments for :meth:`~pyramid.config.Configurator.add_view` can thus be used with the :class:`~pyramid.view.action` decorator to further restrict when the view will be called. One important difference is that a handler method can respond to an ``action`` name that is different from the method name by passing in a ``name`` argument. Example: .. code-block:: python :linenos: from pyramid.view import action class Hello(object): def __init__(self, request): self.request = request @action(name='index', renderer='created.mak', request_method='POST') def create(self): return {} @action(renderer="view_all.mak", request_method='GET') def index(self): return {} This will register two views that require the ``action`` to be ``index``, with the additional view predicate requiring a specific request method. 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: .. code-block:: python :linenos: from pyramid.view import action class Hello(object): def __init__(self, request): self.request = request @action(name='home', renderer='home.mak') @action(name='about', renderer='about.mak') def show_template(self): # prep some template vars return {} # in the config config.add_handler('hello', '/hello/{action}', handler=Hello) With this configuration, the url ``/hello/home`` will find a view configuration that results in calling the ``show_template`` method, then rendering the template with ``home.mak``, and the url ``/hello/about`` will call the same method and render the ``about.mak`` template. .. index:: single: resource interfaces .. _using_resource_interfaces: Using Resource Interfaces In View Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Instead of registering your views with a ``context`` that names a Python resource *class*, you can optionally register a view callable with a ``context`` which is an :term:`interface`. An interface can be attached arbitrarily to any resource object. View lookup treats context interfaces specially, and therefore the identity of a resource can be divorced from that of the class which implements it. As a result, associating a view with an interface can provide more flexibility for sharing a single view between two or more different implementations of a resource type. For example, if two resource objects of different Python class types share the same interface, you can use the same view configuration to specify both of them as a ``context``. In order to make use of interfaces in your application during view dispatch, you must create an interface and mark up your resource classes or instances with interface declarations that refer to this interface. To attach an interface to a resource *class*, you define the interface and use the :func:`zope.interface.implements` function to associate the interface with the class. .. code-block:: python :linenos: from zope.interface import Interface from zope.interface import implements class IHello(Interface): """ A marker interface """ class Hello(object): implements(IHello) To attach an interface to a resource *instance*, you define the interface and use the :func:`zope.interface.alsoProvides` function to associate the interface with the instance. This function mutates the instance in such a way that the interface is attached to it. .. code-block:: python :linenos: from zope.interface import Interface from zope.interface import alsoProvides class IHello(Interface): """ A marker interface """ class Hello(object): pass def make_hello(): hello = Hello() alsoProvides(hello, IHello) return hello Regardless of how you associate an interface, with a resource instance, or a resource 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 "resources.py", the interface declaration below will associate the ``mypackage.views.hello_world`` view with resources that implement, or provide, this interface. .. code-block:: python :linenos: # config is an instance of pyramid.config.Configurator config.add_view('mypackage.views.hello_world', name='hello.html', context='mypackage.resources.IHello') Any time a resource 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, in cases where a view is registered against a resource class, and a view is also registered against an interface that the resource class implements, an ambiguity arises. Views registered for the resource class take precedence over any views registered for any interface the resource class implements. Thus, if one view configuration names a ``context`` of both the class type of a resource, and another view configuration names a ``context`` of interface implemented by the resource's class, and both view configurations are otherwise identical, the view registered for the context's class will "win". For more information about defining resources with interfaces for use within view configuration, see :ref:`resources_which_implement_interfaces`. .. index:: single: view security pair: security; view .. _view_security_section: Configuring View Security ~~~~~~~~~~~~~~~~~~~~~~~~~ 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` resource 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`: .. code-block:: python :linenos: # config is an instance of pyramid.config.Configurator config.add_view('myproject.views.add_entry', name='add.html', context='myproject.resources.IBlog', permission='add') 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 .. _view_lookup: View Lookup and Invocation -------------------------- :term:`View lookup` is the :app:`Pyramid` subsystem responsible for finding an invoking a :term:`view callable`. The view lookup subsystem is passed a :term:`context` and a :term:`request` object. :term:`View configuration` information stored within in the :term:`application registry` is compared against the context and request by the view lookup subsystem in order to find the "best" view callable for the set of circumstances implied by the context and request. Predicate attributes of view configuration can be thought of like "narrowers". In general, the greater number of predicate attributes possessed by a view's configuration, the more specific the circumstances need to be before the registered view callable will be invoked. For any given request, a view with five predicates will always be found and evaluated before a view with two, for example. All predicates must match for the associated view to be called. This does not mean however, that :app:`Pyramid` "stops looking" when it finds a view registration with predicates that don't match. If one set of view predicates does not match, the "next most specific" view (if any) view is consulted for predicates, and so on, until a 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 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 the default notfound view. .. index:: single: debugging not found errors single: not found error (debugging) .. _debug_notfound_section: :exc:`NotFound` Errors ~~~~~~~~~~~~~~~~~~~~~~ It's useful to be able to debug :exc:`NotFound` error responses when they occur unexpectedly due to an application registry misconfiguration. To debug these errors, use the ``PYRAMID_DEBUG_NOTFOUND`` environment variable or the ``debug_notfound`` 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. Further Information ------------------- The chapter entitled :ref:`renderers_chapter` explains how to create functions (or instances/classes) which do not return a :term:`Response` object, yet which still can be used as view callables.