1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
|
Static Assets
=============
:app:`Pyramid` makes it possible to serve up static asset files from a
directory on a filesystem. This chapter describes how to configure
:app:`Pyramid` to do so.
.. index::
single: add_static_view
.. _static_assets_section:
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``.
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*.
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.
.. code-block:: python
:linenos:
# 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`.
.. code-block:: python
:linenos:
# 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
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`.
.. note::
Using :func:`pyramid.url.static_url` in conjunction with a
:meth:`pyramid.config.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.
For example, :meth:`pyramid.config.Configurator.add_static_view` may
be fed a ``name`` argument which is ``http://example.com/images``:
.. code-block:: python
:linenos:
# config is an instance of pyramid.config.Configurator
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.
.. note::
Using :func:`pyramid.url.static_url` in conjunction with a
:meth:`pyramid.configuration.Configurator.add_static_view` makes it
possible to put static media on a separate webserver during production (if
the ``name`` argument to
:meth:`pyramid.configuration.Configurator.add_static_view` is a URL),
while keeping static media package-internal and served by the development
webserver during development (if the ``name`` argument to
:meth:`pyramid.configuration.Configurator.add_static_view` is a view
name). To create such a circumstance, we suggest using the
:attr:`pyramid.registry.Registry.settings` API in conjunction with a
setting in the application ``.ini`` file named ``media_location``. Then
set the value of ``media_location`` to either a view name or a URL
depending on whether the application is being run in development or in
production (use a different `.ini`` file for production than you do for
development). This is just a suggestion for a pattern; any setting name
other than ``media_location`` could be used.
.. index::
single: generating static asset urls
single: static asset urls
.. _generating_static_asset_urls:
Generating Static Asset URLs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When a :meth:`pyramid.config.Configurator.add_static_view` method is used to
register a static asset directory, a special helper API named
:func:`pyramid.url.static_url` can be used to generate the appropriate URL
for an asset that lives in one of the directories named by the static
registration ``path`` attribute.
For example, let's assume you create a set of static declarations like so:
.. code-block:: python
:linenos:
config.add_static_view(name='static1', path='mypackage:assets/1')
config.add_static_view(name='static2', path='mypackage:assets/2')
These declarations create URL-accessible directories which have URLs that
begin with ``/static1`` and ``/static2``, respectively. The assets in the
``assets/1`` directory of the ``mypackage`` package are consulted when a user
visits a URL which begins with ``/static1``, and the assets in the
``assets/2`` directory of the ``mypackage`` package are consulted when a user
visits a URL which begins with ``/static2``.
You needn't generate the URLs to static assets "by hand" in such a
configuration. Instead, use the :func:`pyramid.url.static_url` API to
generate them for you. For example:
.. code-block:: python
:linenos:
from pyramid.url import static_url
from pyramid.chameleon_zpt import render_template_to_response
def my_view(request):
css_url = static_url('mypackage:assets/1/foo.css', request)
js_url = static_url('mypackage:assets/2/foo.js', request)
return render_template_to_response('templates/my_template.pt',
css_url = css_url,
js_url = js_url)
If the request "application URL" of the running system is
``http://example.com``, the ``css_url`` generated above would be:
``http://example.com/static1/foo.css``. The ``js_url`` generated
above would be ``http://example.com/static2/foo.js``.
One benefit of using the :func:`pyramid.url.static_url` function rather than
constructing static URLs "by hand" is that if you need to change the ``name``
of a static URL declaration, the generated URLs will continue to resolve
properly after the rename.
URLs may also be generated by :func:`pyramid.url.static_url` to static assets
that live *outside* the :app:`Pyramid` application. This will happen when
the :meth:`pyramid.config.Configurator.add_static_view` API associated with
the path fed to :func:`pyramid.url.static_url` is a *URL* instead of a view
name. For example, the ``name`` argument may be ``http://example.com`` while
the the ``path`` given may be ``mypackage:images``:
.. code-block:: python
:linenos:
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
``http://example.com/images``:
.. code-block:: python
:linenos:
static_url('mypackage:images/logo.png', request)
# -> http://example.com/images/logo.png
.. index::
single: static assets view
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.
.. ignore-next-block
.. code-block:: python
:linenos:
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.
.. code-block:: python
:linenos:
config.add_view('mypackage.static.static_view', name='static',
context='mypackage.resources.Root')
In this case, ``mypackage.resources.Root`` refers to the class of your
:app:`Pyramid` application's resource tree.
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.
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.
.. warning::
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" (``@@``).
|