This looks reasonable. I think it would also be reasonable to just make this the standard 'view' functionality, since afaict the current functionality is a subset of this.
Chris On Sun, Sep 13, 2009 at 12:57 PM, Chris McDonough <chr...@plope.com> wrote: > Here's some sci fi I wrote up about a "page" ZCML directive. As Tim > Hoffman > suggested, maybe the fact that the "page" is passed into the template would > give us enough "pull" capability to avoid any of the other hacks I proposed > to > push global names into every rendered template. > > Note that the "view" directive could probably eventually be changed to do > everything that the "page" directive I describe below does. > > Comments appreciated. > > repoze.bfg.page README > ====================== > > ``repoze.bfg.page`` is a package which adds a ``page`` ZCML directive > to the set of directives that may be used under BFG. You might use a > ``page`` directive in places where you would otherwise use the > built-in repoze.bfg ``view`` directive. Defining a ``page`` directive > effectively creates a single BFG view "under the hood", and owns > attributes similar to those of a view directive. However, the > ``page`` directive differs from the BFG ``view`` directive in a number > of important ways: > > - The ``page`` directive allows you to associate a *template* with the > page being defined. The machinery behind the ``page`` directive is > capable of rendering an associated template, unlike a view, which > must find and render a template itself. > > - A ``page`` directive, like a BFG ``view`` directive, points at a > callable which accepts two arguments: ``context`` and ``request``. > This callable must return a Response object *or* a Python > dictionary. This is unlike a BFG ``view`` callable, which always > returns a Response object (and must never return a dictionary). > > The ``callable`` which a ``page`` directive points at may optionally > be a class. If the page directive's ``callable`` attribute points > at a class, that class must have an ``__init__`` method that accepts > two arguments: ``context`` and ``request``. That class must further > define a ``__call__`` method which accepts no arguments and which > returns a dictionary or a Response object. > > If the page callable returns a Python dictionary, the ``template`` > named within the directive will be passed the dictionary as its > keyword arguments, and the ``page`` implementation will return the > resulting rendered template in a response to the user. The callable > object (whatever object was used to define the page ``callable``) > will be automatically inserted into the set of keyword arguments > passed to the template as ``page``. If the callable object was a > class, an instance of that class will be inserted into the keyword > arguments as ``page``. > > If the ``callable`` associated with a ``page`` directive returns a > Response object (an object with the attributes ``status``, > ``headerlist`` and ``app_iter``), any template associated with the > ``page`` declaration is ignored, and the response is passed back to > BFG. For example, if your page callable returns an ``HTTPFound`` > response, no template rendering will be performed:: > > from webob.exc import HTTPFound > return HTTPFound(location='http://example.com') # templating avoided > > Here's an example of a page directive which acts as a default view:: > > <page > template="templates/my_template.pt" > callable=".pages.my_page" > /> > > The ``template`` attribute is optional. If one is not named, and the > callable returns a dictionary, an error will be thrown at rendering > time. > > Special ZCML Attributes > ----------------------- > > The directive accepts attributes other than ``template`` and ``callable``. > > attr > > ``repoze.bfg.page`` defaults to using the ``__call__`` method of the > page callable to obtain a response dictionary. The ``attr`` value > allows you to vary that method name. For example, if your class had > a method named ``index`` and you wanted to use this method instead > of ``__call__``, you'd say ``attr="index"`` in the page ZCML > definition. This is most useful when the page definition is a > class. > > for > > A Python dotted-path name representing the Python class that the > :term:`context` must be an instance of, *or* the :term:`interface` > that the :term:`context` must provide in order for this view to be > found and called. > > name > > The *view name*. Read and understand :ref:`traversal_chapter` to > understand the concept of a view name. > > permission > > The name of a *permission* that the user must possess in order to > call the view. See :ref:`view_security_section` for more > information about view security and permissions. > > 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 attribute ensures that the view will only be > called when the request's ``method`` (aka ``REQUEST_METHOD``) string > matches the supplied value. > > request_param > > This value can be any string. A view declaration with this > attribute ensures that the view will only be called when the 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 to the attribute 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. > > containment > > This value should be a Python dotted-path string representing the > class that a graph traversal parent object of the :term:`context` > must be an instance of (or :term:`interface` that a parent object > must provide) in order for this view to be found and called. Your > models must be "location-aware" to use this feature. See > :ref:`location_aware` for more information about location-awareness. > > route_name > > *This attribute services an advanced feature that isn't often used > unless you want to perform traversal *after* a route has matched.* > This value must match the ``name`` of a ``<route>`` declaration (see > :ref:`urldispatch_chapter`) that must match before this view will be > called. The ``<route>`` declaration specified by ``route_name`` must > exist in ZCML before the view that names the route > (XML-ordering-wise) . Note that the ``<route>`` declaration > referred to by ``route_name`` usually has a ``*traverse`` token in > the value of its ``path`` attribute, representing a part of the path > that will be used by traversal against the result of the route's > :term:`root factory`. See :ref:`hybrid_chapter` for more > information on using this advanced feature. > > request_type > > This value should be a Python dotted-path string representing the > :term:`interface` that the :term:`request` must have in order for > this view to be found and called. See > :ref:`view_request_types_section` for more information about request > types. For backwards compatibility with :mod:`repoze.bfg` version > 1.0, this value may also be an HTTP ``REQUEST_METHOD`` string, e.g. > ('GET', 'HEAD', 'PUT', 'POST', or 'DELETE'). Passing request method > strings as a ``request_type`` is deprecated. Use the > ``request_method`` attribute instead for maximum forward > compatibility. > > Special Keyword Names When A Callable Returns A Dictionary > ---------------------------------------------------------- > > Several keyword names in a dictionary return value of a page callable > are treated specially by the page implementation. These values are > passed through to the template during rendering, but they also > influence the response returned to the user separate from any template > rendering. Page callables should set these values into the dictionary > they return to influence response attributes. > > content_type > > Defines the content-type of the resulting response, > e.g. ``text/xml``. > > headerlist > > A sequence of tuples describing cookie values that should be set in > the response, e.g. ``[('Set-Cookie', 'abc=123'), ('X-My-Header', > 'foo')]``. > > status > > A WSGI-style status code (e.g. ``200 OK``) describing the status of > the response. > > charset > > The character set (e.g. ``UTF-8``) of the response. > > cache_for > > A value in seconds which will influence ``Cache-Control`` and > ``Expires`` headers in the returned response. The same can also be > achieved by returning various values in the headerlist, this is > purely a convenience. > > Default Template Filename Extension Mappings > -------------------------------------------- > > A file extension mapping is used to determine which templating system > renderer to use to render any given template. By default, a single > filename-extension-to-renderer mapping is used: any template name with > a filename extension of ".pt" is assumed to be rendered via a > Chameleon ZPT template. > > By default, if a template renderer cannot be recognized by its > extension, it will be assumed that a Chameleon text renderer should be > used to render the template. > > Adding and Overriding Template Filename Extension Mappings > ---------------------------------------------------------- > > Additonal declarations can be made which override a default > file-extension-to-renderer mapping or add a new > file-extension-to-renderer mapping. This is accomplished via one or > more separate ZCML directives. > > For example, to add Jinja2 rendering (after installing the > repoze.bfg.jinja2" package), whereby filenames that end in ``.jinja`` > are rendered by the Jinja2 renderer:: > > <utility provides="repoze.bfg.page.IPageRenderer" > name=".jinja" > component="repoze.bfg.jinja2.render_template_to_response"/> > > To override the default mapping in which files with a ``.pt`` > extension are rendered via a Chameleon ZPT page template renderer, use > a variation on the following:: > > <utility provides="repoze.bfg.page.IPageRenderer" > name=".pt" > component="my.package.pt_renderer"/> > > By default, when a template extension is unrecognized, the Chameleon > text templating engine is assumed. You can override the default > renderer by creating an ``IPageRenderer`` utility which has no > ``name``:: > > <utility provides="repoze.bfg.page.IPageRenderer" > component="my.package.default_renderer"/> > > The ``component`` named within any of these directives must be a > callable which accepts the following arguments: ``(template_name, > request, **kw)``. It must return a Response object. > > _______________________________________________ > Repoze-dev mailing list > Repoze-dev@lists.repoze.org > http://lists.repoze.org/listinfo/repoze-dev >
_______________________________________________ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev