diff options
| -rw-r--r-- | docs/narr/assets.rst | 87 | ||||
| -rw-r--r-- | docs/narr/viewconfig.rst | 4 | ||||
| -rw-r--r-- | pyramid/tests/test_view.py | 14 | ||||
| -rw-r--r-- | pyramid/view.py | 14 |
4 files changed, 117 insertions, 2 deletions
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index d6bc8cbb8..fc02b3f7d 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -512,6 +512,93 @@ time at start up as a cachebust token: .. index:: single: static assets view +CSS and JavaScript source and cache busting +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Often one needs to refer to images and other static assets inside CSS and +JavaScript files. If cache busting is active, the final static asset URL is +not available until the static assets have been assembled. These URLs cannot +be handwritten. Thus, when having static asset references in CSS and +JavaScript, one needs to perform one of the following tasks. + +* Process the files by using a precompiler which rewrites URLs to their final + cache busted form. + +* Templatize JS and CSS, and call ``request.static_url()`` inside their + template code. + +* Pass static URL references to CSS and JavaScript via other means. + +Below are some simple approaches for CSS and JS programming which consider +asset cache busting. These approaches do not require additional tools or +packages. + +Relative cache busted URLs in CSS ++++++++++++++++++++++++++++++++++ + +Consider a CSS file ``/static/theme/css/site.css`` which contains the +following CSS code. + +.. code-block:: css + + body { + background: url(/static/theme/img/background.jpg); + } + +Any changes to ``background.jpg`` would not appear to the visitor because the +URL path is not cache busted as it is. Instead we would have to construct an +URL to the background image with the default ``PathSegmentCacheBuster`` cache +busting mechanism:: + + https://site/static/1eeb262c717/theme/img/background.jpg + +Every time the image is updated, the URL would need to be changed. It is not +practical to write this non-human readable URL into a CSS file. + +However, the CSS file itself is cache busted and is located under the path for +static assets. This lets us use relative references in our CSS to cache bust +the image. + +.. code-block:: css + + body { + background: url(../img/background.jpg); + } + +The browser would interpret this as having the CSS file hash in URL:: + + https://site/static/ab234b262c71/theme/css/../img/background.jpg + +The downside of this approach is that if the background image changes, one +needs to bump the CSS file. The CSS file hash change signals the caches that +the relative URL to the image in the CSS has been changed. When updating CSS +and related image assets, updates usually happen hand in hand, so this does +not add extra effort to theming workflow. + +Passing cache busted URLs to JavaScript ++++++++++++++++++++++++++++++++++++++++ + +For JavaScript, one can pass static asset URLs as function arguments or +globals. The globals can be generated in page template code, having access to +the ``request.static_url()`` function. + +Below is a simple example of passing a cached busted image URL in the Jinja2 +template language. Put the following code into the ``<head>`` section of the +relevant page. + +.. code-block:: html + + <script> + window.assets.backgroundImage = + "{{ '/theme/img/background.jpg'|static_url() }}"; + </script> + +Then in your main ``site.js`` file put the following code. + +.. code-block:: javascript + + var image = new Image(window.assets.backgroundImage); + .. _advanced_static: Advanced: Serving Static Assets Using a View Callable diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index fc5ae6dc6..46b2c4f76 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -119,7 +119,7 @@ Non-Predicate Arguments ``renderer`` Denotes the :term:`renderer` implementation which will be used to construct a :term:`response` from the associated view callable's return value. - + .. seealso:: See also :ref:`renderers_chapter`. This is either a single string term (e.g. ``json``) or a string implying a @@ -1020,7 +1020,7 @@ there's a ``should_cache`` GET or POST variable: @view_config(http_cache=3600) def view(request): response = Response() - if not 'should_cache' in request.params: + if 'should_cache' not in request.params: response.cache_control.prevent_auto = True return response diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py index ff73a93ab..e6b9f9e7e 100644 --- a/pyramid/tests/test_view.py +++ b/pyramid/tests/test_view.py @@ -185,6 +185,20 @@ class RenderViewToResponseTests(BaseTest, unittest.TestCase): self.assertEqual(response.status, '200 OK') self.assertEqual(response.app_iter, ['anotherview']) + def test_call_view_with_request_iface_on_request(self): + # See https://github.com/Pylons/pyramid/issues/1643 + from zope.interface import Interface + class IWontBeFound(Interface): pass + context = self._makeContext() + request = self._makeRequest() + request.request_iface = IWontBeFound + response = DummyResponse('aview') + view = make_view(response) + self._registerView(request.registry, view, 'aview') + response = self._callFUT(context, request, name='aview') + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.app_iter, ['aview']) + class RenderViewToIterableTests(BaseTest, unittest.TestCase): def _callFUT(self, *arg, **kw): from pyramid.view import render_view_to_iterable diff --git a/pyramid/view.py b/pyramid/view.py index 005e81148..2867e3d6f 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -49,6 +49,19 @@ def render_view_to_response(context, request, name='', secure=True): registry = get_current_registry() context_iface = providedBy(context) + # We explicitly pass in the interfaces provided by the request as + # request_iface to _call_view; we don't want _call_view to use + # request.request_iface, because render_view_to_response and friends are + # pretty much limited to finding views that are not views associated with + # routes, and the only thing request.request_iface is used for is to find + # route-based views. The render_view_to_response API is (and always has + # been) a stepchild API reserved for use of those who actually use + # traversal. Doing this fixes an infinite recursion bug introduced in + # Pyramid 1.6a1, and causes the render_view* APIs to behave as they did in + # 1.5 and previous. We should probably provide some sort of different API + # that would allow people to find views for routes. See + # https://github.com/Pylons/pyramid/issues/1643 for more info. + request_iface = providedBy(request) response = _call_view( registry, @@ -57,6 +70,7 @@ def render_view_to_response(context, request, name='', secure=True): context_iface, name, secure=secure, + request_iface=request_iface, ) return response # NB: might be None |
