From 56db9ebbb2443f213cc38911c83de24a5abbb111 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 24 Dec 2010 22:26:16 -0500 Subject: - Changed "Static Assets" narrative chapter: clarify that ``name`` represents a prefix unless it's a URL, added an example of a root-relative static view fallback for URL dispatch, added an example of creating a simple view that returns the body of a file. --- docs/narr/static.rst | 262 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 158 insertions(+), 104 deletions(-) (limited to 'docs') diff --git a/docs/narr/static.rst b/docs/narr/static.rst index 53564a632..e6be5fdff 100644 --- a/docs/narr/static.rst +++ b/docs/narr/static.rst @@ -15,18 +15,18 @@ Serving Static Assets Use the :meth:`pyramid.config.Configurator.add_static_view` to instruct :app:`Pyramid` to serve static assets such as JavaScript and CSS files. This -mechanism makes static files available at a name relative to the application -root URL, e.g. ``/static``. +mechanism makes a directory of static files available at a name relative to +the application root URL, e.g. ``/static`` or as an external URL. -Note that the ``path`` provided to -:meth:`pyramid.config.Configurator.add_static_view` may be a fully qualified -:term:`asset specification`, or an *absolute path*. +.. note:: `~pyramid.config.Configurator.add_static_view` cannot serve a + single file, nor can it serve a directory of static files directly + relative to the root URL of a :app:`Pyramid` application. For these + features, see :ref:`advanced_static`. Here's an example of a use of -:meth:`pyramid.config.Configurator.add_static_view` that will serve -files up under the ``/static`` URL from the ``/var/www/static`` directory of -the computer which runs the :app:`Pyramid` application using an absolute -path. +:meth:`~pyramid.config.Configurator.add_static_view` that will serve files up +from the ``/var/www/static`` directory of the computer which runs the +:app:`Pyramid` application as URLs beneath the ``/static`` URL prefix. .. code-block:: python :linenos: @@ -34,10 +34,30 @@ path. # config is an instance of pyramid.config.Configurator config.add_static_view(name='static', path='/var/www/static') -Here's an example of :meth:`pyramid.config.Configurator.add_static_view` that -will serve files up under the ``/static`` URL from the ``a/b/c/static`` -directory of the Python package named ``some_package`` using a fully -qualified :term:`asset specification`. +The ``name`` prepresents a URL *prefix*. In order for files that live in the +``path`` directory to be served, a URL that requests one of them must begin +with that prefix. In the example above, ``name`` is ``static``, and ``path`` +is ``/var/www/static``. In English, this means that you wish to serve the +files that live in ``/var/www/static`` as sub-URLs of the ``/static`` URL +prefix. Therefore, the file ``/var/www/static/foo.css`` will be returned +when the user visits your application's URL ``/static/foo.css``. + +No authorization is ever required for users to visit files served by a static +view added via :meth:`~pyramid.config.Configurator.add_static_view`. If you +need "static" resources to be protected by authentication services, see +:ref:`advanced_static`. + +A static directory named at ``path`` may contain subdirectories recursively, +and any subdirectories may hold files; these will be resolved by the static +view as you would expect. The ``Content-Type`` header returned by the static +view for each particular type of file is dependent upon its file extension. + +Here's another example that uses an :term:`asset specification` instead of an +absolute path as the ``path`` argument. To convince +:meth:`pyramid.config.Configurator.add_static_view` to serve files up under +the ``/static`` URL from the ``a/b/c/static`` directory of the Python package +named ``some_package``, we can use a fully qualified :term:`asset +specification` as the ``path``: .. code-block:: python :linenos: @@ -45,22 +65,13 @@ qualified :term:`asset specification`. # config is an instance of pyramid.config.Configurator config.add_static_view(name='static', path='some_package:a/b/c/static') -Whether you use for ``path`` a fully qualified asset specification, or an -absolute path, when you place your static files on the filesystem in the -directory represented as the ``path`` of the directive, you will then be able -to view the static files in this directory via a browser at URLs prefixed -with the directive's ``name``. For instance if the ``static`` directive's -``name`` is ``static`` and the static directive's ``path`` is -``/path/to/static``, ``http://localhost:6543/static/foo.js`` will return the -file ``/path/to/static/dir/foo.js``. The static directory may contain -subdirectories recursively, and any subdirectories may hold files; these will -be resolved by the static view as you would expect. - -While the ``path`` argument can be a number of different things, the ``name`` -argument of the call to :meth:`pyramid.config.Configurator.add_static_view` -can also be one of a number of things: a *view name* or a *URL*. The above -examples have shown usage of the ``name`` argument as a view name. When -``name`` is a *URL* (or any string with a slash (``/``) in it), static assets +The ``path`` provided to :meth:`pyramid.config.Configurator.add_static_view` +may be a fully qualified :term:`asset specification`, or an *absolute path*. + +Instead of representing a URL prefix, the ``name`` argument of a call to +:meth:`pyramid.config.Configurator.add_static_view` can alternately be a +*URL*. Each of examples we've seen so far have shown usage of the ``name`` +argument as a URL prefix. However, when ``name`` is a *URL*, static assets can be served from an external webserver. In this mode, the ``name`` is used as the URL prefix when generating a URL using :func:`pyramid.url.static_url`. @@ -74,39 +85,22 @@ be fed a ``name`` argument which is ``http://example.com/images``: config.add_static_view(name='http://example.com/images', path='mypackage:images') -Because :meth:`pyramid.config.Configurator.add_static_view` is -provided with a ``name`` argument that is the URL prefix -``http://example.com/images``, subsequent calls to -:func:`pyramid.url.static_url` with paths that start with the ``path`` -argument passed to :meth:`pyramid.config.Configurator.add_static_view` -will generate a URL something like ``http://example.com/images/logo.png``. The -external webserver listening on ``example.com`` must be itself configured to -respond properly to such a request. The :func:`pyramid.url.static_url` API -is discussed in more detail later in this chapter. - -The :ref:`static_directive` ZCML directive offers an declarative equivalent -to :meth:`pyramid.config.Configurator.add_static_view`. Use of the -:ref:`static_directive` ZCML directive is completely equivalent to using -imperative configuration for the same purpose. +Because :meth:`pyramid.config.Configurator.add_static_view` is provided with +a ``name`` argument that is the URL ``http://example.com/images``, subsequent +calls to :func:`pyramid.url.static_url` with paths that start with the +``path`` argument passed to +:meth:`pyramid.config.Configurator.add_static_view` will generate a URL +something like ``http://example.com/images/logo.png``. The external +webserver listening on ``example.com`` must be itself configured to respond +properly to such a request. The :func:`pyramid.url.static_url` API is +discussed in more detail later in this chapter. .. note:: - Using :func:`pyramid.url.static_url` in conjunction with a - :meth:`pyramid.configuration.Configurator.add_static_view` makes it - possible to put static media on a separate webserver during production (if - the ``name`` argument to - :meth:`pyramid.config.Configurator.add_static_view` is a URL), - while keeping static media package-internal and served by the development - webserver during development (if the ``name`` argument to - :meth:`pyramid.config.Configurator.add_static_view` is a view - name). To create such a circumstance, we suggest using the - :attr:`pyramid.registry.Registry.settings` API in conjunction with a - setting in the application ``.ini`` file named ``media_location``. Then - set the value of ``media_location`` to either a view name or a URL - depending on whether the application is being run in development or in - production (use a different `.ini`` file for production than you do for - development). This is just a suggestion for a pattern; any setting name - other than ``media_location`` could be used. + The :ref:`static_directive` ZCML directive offers an declarative + equivalent to :meth:`pyramid.config.Configurator.add_static_view`. Use of + the :ref:`static_directive` ZCML directive is completely equivalent to + using imperative configuration for the same purpose. .. index:: single: generating static asset urls @@ -175,7 +169,8 @@ the the ``path`` given may be ``mypackage:images``: .. code-block:: python :linenos: - config.add_static_view(name='http://example.com/images', path='mypackage:images') + config.add_static_view(name='http://example.com/images', + path='mypackage:images') Under such a configuration, the URL generated by ``static_url`` for assets which begin with ``mypackage:images`` will be prefixed with @@ -187,24 +182,61 @@ assets which begin with ``mypackage:images`` will be prefixed with static_url('mypackage:images/logo.png', request) # -> http://example.com/images/logo.png +Using :func:`pyramid.url.static_url` in conjunction with a +:meth:`pyramid.configuration.Configurator.add_static_view` makes it possible +to put static media on a separate webserver during production (if the +``name`` argument to :meth:`pyramid.config.Configurator.add_static_view` is a +URL), while keeping static media package-internal and served by the +development webserver during development (if the ``name`` argument to +:meth:`pyramid.config.Configurator.add_static_view` is a URL prefix). To +create such a circumstance, we suggest using the +:attr:`pyramid.registry.Registry.settings` API in conjunction with a setting +in the application ``.ini`` file named ``media_location``. Then set the +value of ``media_location`` to either a prefix or a URL depending on whether +the application is being run in development or in production (use a different +`.ini`` file for production than you do for development). This is just a +suggestion for a pattern; any setting name other than ``media_location`` +could be used. + .. index:: single: static assets view +.. _advanced_static: + Advanced: Serving Static Assets Using a View Callable ----------------------------------------------------- For more flexibility, static assets can be served by a :term:`view callable` -which you register manually. For example, you may want static assets to only -be available when the :term:`context` is of a particular type, or when -certain request headers are present. - -The :class:`pyramid.view.static` helper class is used to perform this -task. This class creates an object that is capable acting as a :app:`Pyramid` -view callable which serves static assets from a directory. For instance, to -serve files within a directory located on your filesystem at -``/path/to/static/dir`` from the URL path ``/static`` in your application, -create an instance of the :class:`pyramid.view.static` class inside a -``static.py`` file in your application root as below. +which you register manually. For example, if you're using :term:`URL +dispatch`, you may want static assets to only be available as a fallback if +no previous route matches. Alternately, you might like to serve a particular +static asset manually, because its download requires authentication. + +Note that you cannot use the :func:`pyramid.url.static_url` API to generate +URLs against assets made accessible by registering a custom static view. + +Root-Relative Custom Static View (URL Dispatch Only) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`pyramid.view.static` helper class generates a Pyramid view +callable. This view callable can serve static assets from a directory. An +instance of this class is actually used by the +:meth:`pyramid.config.Configurator.add_static_view` configuration method, so +its behavior is almost exactly the same once it's configured. + +.. warning:: The following example *will not work* for applications that use + :term:`traversal`, it will only work if you use :term:`URL dispatch` + exclusively. The root-relative route we'll be registering will always be + matched before traversal takes place, subverting any views registered via + ``add_view`` (at least those without a ``route_name``). A + :class:`pyramid.view.static` static view cannot be made root-relative when + you use traversal. + +To serve files within a directory located on your filesystem at +``/path/to/static/dir`` as the result of a "catchall" route hanging from the +root that exists at the end of your routing table, create an instance of the +:class:`pyramid.view.static` class inside a ``static.py`` file in your +application root as below. .. ignore-next-block .. code-block:: python @@ -213,46 +245,68 @@ create an instance of the :class:`pyramid.view.static` class inside a from pyramid.view import static static_view = static('/path/to/static/dir') -.. note:: the argument to :class:`pyramid.view.static` can also be - a "here-relative" pathname, e.g. ``my/static`` (meaning relative to the - Python package of the module in which the view is being defined). - It can also be a :term:`asset specification` - (e.g. ``anotherpackage:some/subdirectory``). - -Subsequently, you may wire this view up to be accessible as ``/static`` using -the :mod:`pyramid.config.Configurator.add_view` method in your application's -startup code against either the class or interface that represents your root -resource object. +.. note:: For better cross-system flexibility, use an :term:`asset + specification` as the argument to :class:`pyramid.view.static` instead of + a physical absolute filesystem path, e.g. ``mypackage:static`` instead of + ``/path/to/mypackage/static``. + +Subsequently, you may wire the files that are served by this view up to be +accessible as ``/`` using a configuration method in your +application's startup code. .. code-block:: python :linenos: - config.add_view('mypackage.static.static_view', name='static', - context='mypackage.resources.Root') + # .. every other add_route and/or add_handler declaration should come + # before this one, as it will, by default, catch all requests -In this case, ``mypackage.resources.Root`` refers to the class of your -:app:`Pyramid` application's resource tree. + config.add_route('catchall_static', '/*subpath', 'myapp.static.static_view') -The context argument above limits where the static view is accessible to URL -paths directly under the root object. If you omit the ``context`` argument, -then ``static`` will be accessible as the static view against any resource -object in the resource tree. This will allow ``/static/foo.js`` to work, but -it will also allow for ``/anything/static/foo.js`` too, as long as -``anything`` can be resolved. +The special name ``*subpath`` above is used by the +:class:`pyramid.view.static` view callable to signify the path of the file +relative to the directory you're serving. -Note that you cannot use the :func:`pyramid.url.static_url` API to generate -URLs against assets made accessible by registering a custom static view. +Registering A View Callable to Serve a "Static" Asset +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can register a simple view callable to serve a single static asset. To +do so, do things "by hand". First define the view callable. -.. warning:: +.. code-block:: python + :linenos: + + import os + from pyramid.view import view_config + from webob import Response + + def favicon_view(request): + here = os.path.dirname(__file__) + icon = open(os.path.join(here, 'static', 'favicon.ico')) + return Response(content_type='image/x-icon', app_iter=icon) + +The above bit of code within ``favicon_view`` computes "here", which is a +path relative to the Python file in which the function is defined. It then +uses the Python ``open`` function to obtain a file handle to a file within +"here" named ``static``, and returns a response using the open the file +handle as the response's ``app_iter``. It makes sure to set the right +content_type too. + +You might register such a view via configuration as a view callable that +should be called as the result of a traversal: + +.. code-block:: python + :linenos: + + config.add_view('myapp.views.favicon_view', name='favicon.ico') + +Or you might register it to be the view callable for a particular route: + +.. code-block:: python + :linenos: - When adding a static view to your root object, you need to be careful that - there are no resource objects contained in the root with the same key as - the view name (e.g., ``static``). Resource objects take precedence during - traversal, thus such a name collision will cause the resource to "shadow" - your static view. To avoid this issue, and ensure that your root - resource's ``__getitem__`` is never called when a static asset is - requested, you can refer to them unambiguously using the ``@@`` prefix - (goggles) in their URLs. For the above examples you could use - '/@@static/foo.js' instead of '/static/foo.js' to avoid such shadowing. - See :ref:`traversal_chapter` for information about "goggles" (``@@``). + config.add_route('favicon', '/favicon.ico', + view='myapp.views.favicon_view') +Because this is a simple view callable, it can be protected with a +:term:`permission` or can be configured to respond under different +circumstances using :term:`view predicate` arguments. -- cgit v1.2.3