diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-09-16 19:24:28 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-09-16 19:24:28 +0000 |
| commit | 862e0824d9b830502ae3d691e2ab5416c82c7b8e (patch) | |
| tree | 6222462f86bb7300774bf5cd6e27b414ed065dbf /docs | |
| parent | 470737a5f5a7d86b809b260b9dbc09f266d4b69c (diff) | |
| download | pyramid-862e0824d9b830502ae3d691e2ab5416c82c7b8e.tar.gz pyramid-862e0824d9b830502ae3d691e2ab5416c82c7b8e.tar.bz2 pyramid-862e0824d9b830502ae3d691e2ab5416c82c7b8e.zip | |
Review and edit views chapter.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/glossary.rst | 25 | ||||
| -rw-r--r-- | docs/narr/views.rst | 415 |
2 files changed, 252 insertions, 188 deletions
diff --git a/docs/glossary.rst b/docs/glossary.rst index 46b94d62d..995049ca9 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -27,6 +27,12 @@ Glossary Resource Any file contained within a Python :term:`package` which is *not* a Python source code file. + Resource Specification + A colon-delimited identifier for a resource. The colon separates + a Python :term:`package` name from a package subpath. For + example, the resource specification ``my.package:static/baz.css`` + identifies the file named ``baz.css`` in the ``static`` + subdirectory of the ``my.package`` Python package. Package A directory on disk which contains an ``__init__.py`` file, making it recognizable to Python as a location which can be ``import`` -ed. @@ -61,6 +67,14 @@ Glossary is the primary mechanism by which a developer writes user interface code within :mod:`repoze.bfg`. See :ref:`views_chapter` for more information about :mod:`repoze.bfg` views. + View Configuration + View configuration is the act of associating a view callable with + configuration information. This configuration information helps + map the view callable to URLs and can influence the response of a + view callable. :mod:`repoze.bfg` views can be configured via + :term:`ZCML` or by a special ``@bfg_view`` decorator. See + :ref:`views_chapter` for more information about view + configuration. View name The "URL name" of a view, e.g ``index.html``. If a view is configured without a name, its name is considered to be the empty @@ -398,3 +412,14 @@ Glossary SQLAlchemy `SQLAlchemy' <http://www.sqlalchemy.org/>`_ is an object relational mapper used in tutorials within this documentation. + JSON + `JavaScript Object Notation <http://www.json.org/>`_ is a data + serialization format. + Renderer + A registered serializer that can be configured via :term:`view + configuration` which converts a non-:term:`Response` return values + from a :term:`view` into a string (and ultimately a response). + Using a renderer can make writing views that require templating or + other serialization less tedious. See + :ref:`views_which_use_a_renderer` for more information. + diff --git a/docs/narr/views.rst b/docs/narr/views.rst index 888337b17..d46ce5f3e 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -8,18 +8,17 @@ your application. The primary job of any :mod:`repoze.bfg` application is is to find and call a :term:`view` when a :term:`request` reaches it. -A view callable may either return a :term:`WebOb` ``Response`` object -directly, or it may return another arbitrary value. If a view -callable returns a non-Response result, the result will be renderered -to a response by the :term:`renderer` associated with the view -configuration for the view. If no renderer is associated with a view, -and that view returns a non-Response object, an error is eventually -raised. - -A view is "configured" via :term:`ZCML` or via a decorator. Either -mechanism is equivalent. The result of making a view declaration in -ZCML or by attaching a view decorator to a Python object that you'd -like to act as a view is known as :term:`view configuration`. +A view callable may always return a :term:`WebOb` ``Response`` object +directly. It may optionally return another arbitrary non-`Response` +value. If a view callable returns a non-Response result, the result +will be converted into a response by the :term:`renderer` associated +with the :term:`view configuration` for the view. + +A view is mapped to one or more URLs by virtue of :term:`view +configuration`. View configuration is performed by adding statements +to your :term:`ZCML` application registry or by attaching +``@bfg_view`` decorators to Python objects in your application source +code. Either mechanism is equivalent. .. _function_as_view: @@ -52,7 +51,7 @@ than when it is a function or another non-class callable. When a view is a class, the class' ``__init__`` is called with the context and the request parameters. As a result, an instance of the class is created. Subsequently, that instance's ``__call__`` method is invoked with no -parameters. The class' ``__call__`` method must return a response. +parameters. Views defined as classes must have the following traits: - an ``__init__`` method that accepts a ``context`` and a ``request`` as positional arguments. @@ -81,27 +80,15 @@ types of objects as described in :ref:`function_as_view`. If you'd like to use a different attribute than ``__call__`` to represent the method expected to return a response, you can use an ``attr`` value as part of view configuration. See -:ref:`the_view_zcml_directive`. +:ref:`view_configuration`. -Arguments Passed to a View --------------------------- - -The :term:`context` and :term:`request` arguments passed to a view -function can be defined as follows: - -context - - An instance of a :term:`context` found via graph :term:`traversal` - or :term:`URL dispatch`. If the context is found via traversal, it - will be a :term:`model` object. - -request - - A WebOb request object representing the current WSGI request. +Request-Only View Definitions +----------------------------- -Views may alternately be defined as callables that accept only a -*request* object, instead of both a context and a request. The -following types work as views in this style: +View callables may alternately be defined as classes or functions (or +any callable) that accept only a *request* object, instead of both a +context and a request. The following types work as views in this +style: #. Functions that accept a single argument ``request``, e.g.:: @@ -135,15 +122,32 @@ code itself. The view always has access to the context via ``request.context`` in any case, so it's still available even if you use the request-only calling convention. +Arguments Passed to a View +-------------------------- + +The :term:`context` and :term:`request` arguments passed to a view +function can be defined as follows: + +context + + An instance of a :term:`context` found via graph :term:`traversal` + or :term:`URL dispatch`. If the context is found via traversal, it + will be a :term:`model` object. + +request + + A WebOb Request object representing the current WSGI request. + .. _the_response: -The Response ------------- +View Responses +-------------- -A view callable may return an object that implements the :term:`WebOb` -``Response`` interface. The easiest way to return something that -implements this interface is to return a ``webob.Response`` object. -But any object that has the following attributes will work: +A view callable may always return an object that implements the +:term:`WebOb` ``Response`` interface. The easiest way to return +something that implements this interface is to return a +``webob.Response`` object. But any object that has the following +attributes will work: status @@ -166,8 +170,8 @@ app_iter If a view happens to return something to the :mod:`repoze.bfg` :term:`router` which does not implement this interface, BFG will attempt to use an associated :term:`renderer` to construct a response. -The specific renderer used can be varied by changing the ``renderer`` -attribute in the view configuration. See +The associated renderer can be varied for a view by changing the +``renderer`` attribute in the view's configuration. See :ref:`views_which_use_a_renderer`. .. _views_which_use_a_renderer: @@ -180,17 +184,31 @@ Writing Views Which Use a Renderer Views needn't always return a WebOb Response object. Instead, they may return an arbitrary Python object, with the expectation that a :term:`renderer` will convert that object into a response on behalf of -the developer. +the developer. Some renderers use a templating system; other +renderers use object serialization techniques. + +If you do not define a ``renderer`` attribute in view configuration +for a view, no renderer is associated with the view. In such a +configuration, an error is raised when a view does not return an +object which implements :term:`Response` interface. View configuration can vary the renderer associated with a view via -the ``renderer`` attribute. The default renderer is the null renderer -(meaning no rendering is done). There is a ``json`` renderer, which -renders view return values to :term:`JSON`. Other built-in renderers -include renderers which use the :term:`Chameleon` templating language -to render a dictionary to a response. See :ref:`build_in_renders` for -the available built-in renders. Renderers can be added to the system -as necessary via ZCML directives (see -:ref:`adding_and_overriding_renderers`). +the ``renderer`` attribute. For example, this ZCML associates the +``json`` renderer with a view: + +.. code-block:: python + :linenos: + + <view + view=".views.my_view" + renderer="json" + /> + +There is a ``json`` renderer, which renders view return values to a +:term:`JSON` serialization. Other built-in renderers include +renderers which use the :term:`Chameleon` templating language to +render a dictionary to a response. See :ref:`built_in_renders` for +the available built-in renderers. If the ``view`` callable associated with a ``view`` directive returns a Response object (an object with the attributes ``status``, @@ -205,10 +223,22 @@ BFG unmolested. For example, if your page callable returns an from webob.exc import HTTPFound return HTTPFound(location='http://example.com') # renderer avoided +Additional renderers can be added to the system as necessary via a +ZCML directive (see :ref:`adding_and_overriding_renderers`). + +.. _view_configuration: + +View Configuration: Mapping Views to URLs +----------------------------------------- + +View "configuration" may be performed in one of two ways: by adding +declarations to your :term:`application registry` (ZCML) or by using +the ``@bfg_view`` decorator. Both methods are explained below. + .. _mapping_views_to_urls_using_zcml_section: -Mapping Views to URLs Using ZCML --------------------------------- +View Configuration Via ZCML +~~~~~~~~~~~~~~~~~~~~~~~~~~~ You may associate a view with a URL by adding information to your :term:`application registry` via :term:`ZCML` in your @@ -278,17 +308,17 @@ apply for the class which is named. .. _the_view_zcml_directive: The ``view`` ZCML Directive -~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++++++++++++++++++++++++++++ The ``view`` ZCML directive has these possible attributes: view The Python dotted-path name to the view callable. This attribute is - required unless a ``template`` attribute also exists. If a - ``template`` attribute exists on the directive, this attribute + required unless a ``renderer`` attribute also exists. If a + ``renderer`` attribute exists on the directive, this attribute defaults to a view that returns an empty dictionary (see - :ref:`views_with_templates`). + :ref:`views_which_use_a_renderer`). for @@ -324,19 +354,21 @@ attr renderer - This is either a single term (e.g. ``json``) or a string implying a - path (e.g. ``templates/views.pt``). If the renderer is a single - term, the specified term will be used to look up a renderer - implementation, and that renderer inplementation will be used to - construct a response from the view return value. If the renderer - term 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. The renderer implementation will be used to - construct a response from the view return value. + This is either a single string term (e.g. ``json``) or a string + implying a path or :term:`resource specification` + (e.g. ``templates/views.pt``). If the renderer value is a single + term (does not contain a dot ``.``), the specified term will be used + to look up a renderer implementation, and that renderer + inplementation will be used to construct a response from the view + return value. If the renderer term 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. The renderer + implementation will be used to construct a response from the view + return value. Note that if the view itself returns a response (see - :ref:`the_response), the specified renderer implementation is never + :ref:`the_response`), the specified renderer implementation is never called. When the renderer is a path, although a path is usually just a @@ -344,8 +376,8 @@ renderer template named "foo.pt" is in the "templates" directory relative to the directory in which the ZCML file is defined), 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:`resource` - "specification" in the form + Windows. The path can alternately be a :term:`resource + specification` in the form ``some.dotted.package_name:relative/path``, making it possible to address template resources which live in a separate package. @@ -440,8 +472,8 @@ request_type .. _mapping_views_to_urls_using_a_decorator_section: -Mapping Views to URLs Using a Decorator ---------------------------------------- +View Configuration Using the ``@bfg_view`` Decorator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you're allergic to reading and writing :term:`ZCML`, or you're just more comfortable defining your view declarations using Python, you may @@ -452,18 +484,18 @@ purpose. ``repoze.bfg.view.bfg_view`` can be used to associate ``containment``, ``request_param`` and ``request_type``, ``attr``, ``renderer``, and ``wrapper`` information -- as done via the equivalent ZCML -- with a function that acts as a :mod:`repoze.bfg` -view. All ZCML attributes are available in decorator form and mean -precisely the same thing. +view. All ZCML attributes (save for the ``view`` attribute) are +available in decorator form and mean precisely the same thing. -To make :mod:`repoze.bfg` process your ``bfg_view`` declarations, you +To make :mod:`repoze.bfg` process your ``@bfg_view`` declarations, you *must* insert the following boilerplate into your application's ``configure.zcml``:: <scan package="."/> After you do so, you will not need to use any other ZCML to configure -:mod:`repoze.bfg` view declarations. Instead, you will use a -decorator to do this work. +:mod:`repoze.bfg` view declarations. Instead, you will be able to use +the ``@bfg_view`` decorator to do this work. .. warning:: using this feature tends to slows down application startup slightly, as more work is performed at application startup @@ -475,7 +507,7 @@ decorator to do this work. about building extensible applications. The ``bfg_view`` Decorator -~~~~~~~~~~~~~~~~~~~~~~~~~~ +++++++++++++++++++++++++++ ``repoze.bfg.view.bfg_view`` is a decorator which allows Python code to make view registrations instead of using ZCML for the same purpose. @@ -517,8 +549,8 @@ 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). -If ``renderer`` is not supplied, ``None`` is used (meaning that the -null renderer is associated with this view). +If ``renderer`` is not supplied, ``None`` is used (meaning that no +renderer is associated with this view). If ``request_type`` is not supplied, the value ``None`` is used, implying any request type. Otherwise, this should be a class or @@ -667,13 +699,101 @@ to convert non-response return values from a view. The value of the ``attr`` attribute represents the attribute name looked up on the view object to return a response. +.. _using_model_interfaces: + +Using Model Interfaces +---------------------- + +Instead of registering your views ``for`` a Python model *class*, you +can optionally register a view for an :term:`interface`. Since an +interface can be attached arbitrarily to any model instance (as +opposed to its identity being implied by only its class), associating +a view with an interface can provide more flexibility for sharing a +single view between two or more different implementations of a model +type. For example, if two model object instances of different Python +class types share the same interface, you can use the same view +against each of them. + +In order to make use of interfaces in your application during view +dispatch, you must create an interface and mark up your model classes +or instances with interface declarations that refer to this interface. + +To attach an interface to a model *class*, you define the interface +and use the ``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 model *instance*, you define the interface +and use the ``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 model instance or +a model class, the resulting ZCML to associate that interface with a +view is the same. Assuming the above code that defines an ``IHello`` +interface lives in the root of your application, and its module is +named "models.py", the below interface declaration will associate the +``.views.hello_world`` view with models that implement (aka provide) +this interface. + +.. code-block:: xml + :linenos: + + <view + for=".models.IHello" + view=".views.hello_world" + name="hello.html" + /> + +Any time a model that is determined to be the :term:`context` provides +this interface, and a view named ``hello.html`` is looked up against +it as per the URL, the ``.views.hello_world`` view will be invoked. + +Note that views registered against a model class take precedence over +views registered for any interface the model class implements when an +ambiguity arises. If a view is registered for both the class type of +the context and an interface implemented by the context's class, the +view registered for the context's class will "win". + +See :term:`Interface` in the glossary to find more information about +interfaces. + .. _built_in_renders: Built-In Renderers ------------------ -Several built-in renderers exist in BFG. These renderers can be used -in the ``renderer`` attribute of view configurations. +Several built-in "renderers" exist in :mod:`repoze.bfg`. These +renderers can be used in the ``renderer`` attribute of view +configurations. ``json``: JSON Renderer ~~~~~~~~~~~~~~~~~~~~~~~ @@ -731,15 +851,18 @@ attributes by attaching properties to the request. See Two built-in renderers exist for :term:`Chameleon` templates. -If the ``renderer`` attribute of a view configuration is a path which -has a final path element with a filename extension of ``.pt``, the -Chameleon ZPT renderer is used. See :ref:`chameleon_zpt_templates` -for more information about ZPT templates. +If the ``renderer`` attribute of a view configuration is an absolute +path, a relative path or :term:`resource specification` which has a +final path element with a filename extension of ``.pt``, the Chameleon +ZPT renderer is used. See :ref:`chameleon_zpt_templates` for more +information about ZPT templates. -If the ``renderer`` attribute of a view configuration is a path which -has a final path element with a filename extension of ``.txt``, the -Chameleon text renderer is used. See :ref:`chameleon_zpt_templates` -for more information about Chameleon text templates. +If the ``renderer`` attribute of a view configuration is an absolute +path, a source-file relative path, or a :term:`resource specification` +which has a final path element with a filename extension of ``.txt``, +the Chameleon text renderer is used. See +:ref:`chameleon_zpt_templates` for more information about Chameleon +text templates. The behavior of these renderers is the same, except for the engine used to render the template. @@ -749,19 +872,22 @@ When a ``renderer`` attribute that names a Chameleon template path must return a Response object or a Python *dictionary*. If the view callable with an associated template returns a Python dictionary, the named template will be passed the dictionary as its keyword arguments, -and the view implementation will return the resulting rendered -template in a response to the user. - -The callable object (whatever object was used to define the ``view``) -will be automatically inserted into the set of keyword arguments -passed to the template as the ``view`` keyword. If the view callable -was a class, the ``view`` keyword will be an instance of that class. -Also inserted into the keywords passed to the template are -``template_name`` (the name of the template, which may be a full path -or a package-relative name, typically the full string used in the -``renderer`` atttribute of the directive), ``context`` (the context of -the view used to render the template), and ``request`` (the request -passed to the view used to render the template). +and the template renderer implementation will return the resulting +rendered template in a response to the user. If the view returns +anything but a dictionary, an error will be raised. + +Before passing keywords to the template, the keywords derived from the +dictionary returned by the view are augumented. The callable object +(whatever object was used to define the ``view``) will be +automatically inserted into the set of keyword arguments passed to the +template as the ``view`` keyword. If the view callable was a class, +the ``view`` keyword will be an instance of that class. Also inserted +into the keywords passed to the template are ``template_name`` (the +name of the template, which may be a full path or a package-relative +name, typically the full string used in the ``renderer`` atttribute of +the directive), ``context`` (the context of the view used to render +the template), and ``request`` (the request passed to the view used to +render the template). Here's an example view configuration which uses a Chameleon ZPT renderer: @@ -793,93 +919,6 @@ Views with use a Chameleon renderer can vary response attributes by attaching properties to the request. See :ref:`response_request_attrs`. -.. _using_model_interfaces: - -Using Model Interfaces ----------------------- - -Instead of registering your views ``for`` a Python model *class*, you -can optionally register a view for an :term:`interface`. Since an -interface can be attached arbitrarily to any model instance (as -opposed to its identity being implied by only its class), associating -a view with an interface can provide more flexibility for sharing a -single view between two or more different implementations of a model -type. For example, if two model object instances of different Python -class types share the same interface, you can use the same view -against each of them. - -In order to make use of interfaces in your application during view -dispatch, you must create an interface and mark up your model classes -or instances with interface declarations that refer to this interface. - -To attach an interface to a model *class*, you define the interface -and use the ``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 model *instance*, you define the interface -and use the ``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 model instance or -a model class, the resulting ZCML to associate that interface with a -view is the same. Assuming the above code that defines an ``IHello`` -interface lives in the root of your application, and its module is -named "models.py", the below interface declaration will associate the -``.views.hello_world`` view with models that implement (aka provide) -this interface. - -.. code-block:: xml - :linenos: - - <view - for=".models.IHello" - view=".views.hello_world" - name="hello.html" - /> - -Any time a model that is determined to be the :term:`context` provides -this interface, and a view named ``hello.html`` is looked up against -it as per the URL, the ``.views.hello_world`` view will be invoked. - -Note that views registered against a model class take precedence over -views registered for any interface the model class implements when an -ambiguity arises. If a view is registered for both the class type of -the context and an interface implemented by the context's class, the -view registered for the context's class will "win". - -See :term:`Interface` in the glossary to find more information about -interfaces. - .. _view_security_section: View Security |
