Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'release/0.6b3'

  • Loading branch information...
commit 1344336bb2b83666e51119393d956dadb9f386d2 2 parents 253efbb + 675af3d
@jezdez jezdez authored
View
2  compressor/__init__.py
@@ -1,4 +1,4 @@
-VERSION = (0, 6, 0, "b", 2) # following PEP 386
+VERSION = (0, 6, 0, "b", 3) # following PEP 386
DEV_N = None
View
8 compressor/base.py
@@ -1,4 +1,5 @@
import os
+import socket
from itertools import chain
from django.template.loader import render_to_string
@@ -31,8 +32,8 @@ def get_filename(self, url):
base_url = settings.COMPRESS_URL
if not url.startswith(base_url):
raise UncompressableFileError(
- "'%s' is not in COMPRESS_URL ('%s') and can not be compressed"
- % (url, base_url))
+ "'%s' isn't accesible via COMPRESS_URL ('%s') and can't be"
+ " compressed" % (url, base_url))
basename = url.replace(base_url, "", 1)
filename = os.path.join(settings.COMPRESS_ROOT, basename)
if not os.path.exists(filename):
@@ -57,7 +58,8 @@ def mtimes(self):
def cachekey(self):
cachestr = "".join(
chain([self.content], self.mtimes)).encode(self.charset)
- return "django_compressor.%s" % get_hexdigest(cachestr)[:12]
+ return "django_compressor.%s.%s" % (socket.gethostname(),
+ get_hexdigest(cachestr)[:12])
@cached_property
def storage(self):
View
9 compressor/cache.py
@@ -1,4 +1,5 @@
import os
+import socket
from django.core.cache import get_cache
from django.utils.encoding import smart_str
@@ -10,11 +11,13 @@ def get_hexdigest(plaintext):
return sha_constructor(plaintext).hexdigest()
def get_mtime_cachekey(filename):
- return "django_compressor.mtime.%s" % get_hexdigest(filename)
+ return "django_compressor.mtime.%s.%s" % (socket.gethostname(),
+ get_hexdigest(filename))
def get_offline_cachekey(source):
- return ("django_compressor.offline.%s" %
- get_hexdigest("".join(smart_str(s) for s in source)))
+ return ("django_compressor.offline.%s.%s" %
+ (socket.gethostname(),
+ get_hexdigest("".join(smart_str(s) for s in source))))
def get_mtime(filename):
if settings.COMPRESS_MTIME_DELAY:
View
23 compressor/finders.py
@@ -0,0 +1,23 @@
+from django.core.exceptions import ImproperlyConfigured
+
+from compressor.conf import settings
+from compressor.storage import CompressorFileStorage
+
+if "django.contrib.staticfiles" in settings.INSTALLED_APPS:
+ from django.contrib.staticfiles.finders import BaseStorageFinder
+elif "staticfiles" in settings.INSTALLED_APPS:
+ from staticfiles import BaseStorageFinder
+else:
+ raise ImproperlyConfigured("When using the compressor staticfiles finder"
+ "either django.contrib.staticfiles or the "
+ "standalone version django-staticfiles needs "
+ "to be installed.")
+
+class CompressorFinder(BaseStorageFinder):
+ """
+ A staticfiles finder that looks in COMPRESS_ROOT
+ for compressed files, to be used during development
+ with staticfiles development file server or during
+ deployment.
+ """
+ storage = CompressorFileStorage
View
82 compressor/settings.py
@@ -13,7 +13,7 @@ class CompressorSettings(AppSettings):
VERBOSE = False
# the backend to use when parsing the JavaScript or Stylesheet files
PARSER = 'compressor.parser.BeautifulSoupParser'
- OUTPUT_DIR = 'cache'
+ OUTPUT_DIR = 'CACHE'
STORAGE = 'compressor.storage.CompressorFileStorage'
CSS_COMPRESSOR = "compressor.css.CssCompressor"
@@ -53,58 +53,40 @@ class CompressorSettings(AppSettings):
def configure_enabled(self, value):
return value or getattr(settings, 'COMPRESS', value)
- def configure_url(self, value):
- # Uses the 1.3 STATIC_URL setting by default
- url = getattr(settings, 'STATIC_URL', value)
- # Check for emptyness since STATIC_URL can be None and ''
- if url:
- # Then on to extensive testing
- root = getattr(settings, 'STATIC_ROOT', None)
- if not root:
- raise ImproperlyConfigured('The COMPRESS_ROOT setting (or its '
- 'fallback STATIC_ROOT) must be set.')
- # In case staticfiles is used, make sure COMPRESS_URL can be used
- # by checking if the the FileSystemFinder is installed, and if is
- # checking if COMPRESS_ROOT is in STATICFILES_DIRS to allow finding
- # compressed files.
- if ("staticfiles" in self.INSTALLED_APPS or
- "django.contrib.staticfiles" in self.INSTALLED_APPS):
- try:
- from staticfiles.conf import settings as staticfiles_settings
- finders = staticfiles_settings.STATICFILES_FINDERS
- standalone = True
- except ImportError:
- finders = []
- standalone = False
- if not finders:
- finders = getattr(settings, 'STATICFILES_FINDERS', [])
- if ("django.contrib.staticfiles.finders.FileSystemFinder" not in finders and
- "staticfiles.finders.FileSystemFinder" not in finders):
- raise ImproperlyConfigured(
- 'Please enable the FileSystemFinder finder of the '
- 'staticfiles app to use it with django_compressor.')
- abs_paths = []
- output_path = os.path.join(root, self.COMPRESS_OUTPUT_DIR)
- for path in getattr(settings, 'STATICFILES_DIRS', []):
- if isinstance(path, tuple) or isinstance(path, list): # stupid Python 2.4
- path = path[1] # in case the STATICFILES_DIRS setting has a prefix
- abs_paths.append(os.path.abspath(path))
- if os.path.abspath(output_path) not in abs_paths:
- extension = ((self.COMPRESS_OUTPUT_DIR, output_path),)
- if standalone:
- from staticfiles.conf import settings as staticfiles_settings
- staticfiles_settings.STATICFILES_DIRS += extension
- else:
- settings.STATICFILES_DIRS += extension
- else:
- # Fallback to good ol' times of ambiguity
- url, root = settings.MEDIA_URL, settings.MEDIA_ROOT
+ def configure_root(self, value):
+ if value is None:
+ value = getattr(settings, 'STATIC_ROOT', None)
+ if not value:
+ value = settings.MEDIA_ROOT
+ if not value:
+ raise ImproperlyConfigured("The COMPRESS_ROOT setting must be set.")
+ # In case staticfiles is used, make sure the FileSystemFinder is
+ # installed, and if it is, check if COMPRESS_ROOT is listed in
+ # STATICFILES_DIRS to allow finding compressed files
+ staticfiles_settings = None
+ if "staticfiles" in self.INSTALLED_APPS:
+ from staticfiles.conf import settings as staticfiles_settings
+ elif "django.contrib.staticfiles" in self.INSTALLED_APPS:
+ staticfiles_settings = settings
+ if staticfiles_settings is not None:
+ if ("compressor.finders.CompressorFinder" not in
+ staticfiles_settings.STATICFILES_FINDERS):
+ raise ImproperlyConfigured(
+ "When using django_compressor together with staticfiles, "
+ "please add 'compressor.finders.CompressorFinder' to the "
+ "STATICFILES_FINDERS setting.")
+ return value
- if not url.endswith('/'):
+ def configure_url(self, value):
+ # Falls back to the 1.3 STATIC_URL setting by default or falls back to MEDIA_URL
+ if value is None:
+ value = getattr(settings, 'STATIC_URL', None)
+ if not value:
+ value = settings.MEDIA_URL
+ if not value.endswith('/'):
raise ImproperlyConfigured('The URL settings (e.g. COMPRESS_URL) '
'must have a trailing slash.')
- self.COMPRESS_ROOT = root
- return url
+ return value
def configure_cache_backend(self, value):
if value is None:
View
30 compressor/tests/tests.py
@@ -1,5 +1,6 @@
import os
import re
+import socket
from BeautifulSoup import BeautifulSoup
try:
@@ -65,14 +66,15 @@ def test_css_return_if_off(self):
self.assertEqual(self.css, self.css_node.output())
def test_cachekey(self):
- is_cachekey = re.compile(r'django_compressor\.\w{12}')
- self.assert_(is_cachekey.match(self.css_node.cachekey), "cachekey is returning something that doesn't look like r'django_compressor\.\w{12}'")
+ host_name = socket.gethostname()
+ is_cachekey = re.compile(r'django_compressor\.%s\.\w{12}' % host_name)
+ self.assert_(is_cachekey.match(self.css_node.cachekey), "cachekey is returning something that doesn't look like r'django_compressor\.%s\.\w{12}'" % host_name)
def test_css_hash(self):
self.assertEqual('f7c661b7a124', self.css_node.hash)
def test_css_return_if_on(self):
- output = u'<link rel="stylesheet" href="/media/cache/css/f7c661b7a124.css" type="text/css">'
+ output = u'<link rel="stylesheet" href="/media/CACHE/css/f7c661b7a124.css" type="text/css">'
self.assertEqual(output, self.css_node.output().strip())
def test_js_split(self):
@@ -104,7 +106,7 @@ def test_js_return_if_off(self):
settings.COMPRESS_ENABLED = enabled
def test_js_return_if_on(self):
- output = u'<script type="text/javascript" src="/media/cache/js/3f33b9146e12.js" charset="utf-8"></script>'
+ output = u'<script type="text/javascript" src="/media/CACHE/js/3f33b9146e12.js" charset="utf-8"></script>'
self.assertEqual(output, self.js_node.output())
def test_custom_output_dir(self):
@@ -284,7 +286,7 @@ def test_css_tag(self):
{% endcompress %}
"""
context = { 'MEDIA_URL': settings.COMPRESS_URL }
- out = u'<link rel="stylesheet" href="/media/cache/css/f7c661b7a124.css" type="text/css">'
+ out = u'<link rel="stylesheet" href="/media/CACHE/css/f7c661b7a124.css" type="text/css">'
self.assertEqual(out, render(template, context))
def test_nonascii_css_tag(self):
@@ -294,7 +296,7 @@ def test_nonascii_css_tag(self):
{% endcompress %}
"""
context = { 'MEDIA_URL': settings.COMPRESS_URL }
- out = '<link rel="stylesheet" href="/media/cache/css/1c1c0855907b.css" type="text/css">'
+ out = '<link rel="stylesheet" href="/media/CACHE/css/1c1c0855907b.css" type="text/css">'
self.assertEqual(out, render(template, context))
def test_js_tag(self):
@@ -304,7 +306,7 @@ def test_js_tag(self):
{% endcompress %}
"""
context = { 'MEDIA_URL': settings.COMPRESS_URL }
- out = u'<script type="text/javascript" src="/media/cache/js/3f33b9146e12.js" charset="utf-8"></script>'
+ out = u'<script type="text/javascript" src="/media/CACHE/js/3f33b9146e12.js" charset="utf-8"></script>'
self.assertEqual(out, render(template, context))
def test_nonascii_js_tag(self):
@@ -314,7 +316,7 @@ def test_nonascii_js_tag(self):
{% endcompress %}
"""
context = { 'MEDIA_URL': settings.COMPRESS_URL }
- out = u'<script type="text/javascript" src="/media/cache/js/5d5c0e1cb25f.js" charset="utf-8"></script>'
+ out = u'<script type="text/javascript" src="/media/CACHE/js/5d5c0e1cb25f.js" charset="utf-8"></script>'
self.assertEqual(out, render(template, context))
def test_nonascii_latin1_js_tag(self):
@@ -324,7 +326,7 @@ def test_nonascii_latin1_js_tag(self):
{% endcompress %}
"""
context = { 'MEDIA_URL': settings.COMPRESS_URL }
- out = u'<script type="text/javascript" src="/media/cache/js/40a8e9ffb476.js" charset="utf-8"></script>'
+ out = u'<script type="text/javascript" src="/media/CACHE/js/40a8e9ffb476.js" charset="utf-8"></script>'
self.assertEqual(out, render(template, context))
def test_compress_tag_with_illegal_arguments(self):
@@ -351,7 +353,7 @@ def test_css_tag_with_storage(self):
{% endcompress %}
"""
context = { 'MEDIA_URL': settings.COMPRESS_URL }
- out = u'<link rel="stylesheet" href="/media/cache/css/5b231a62e9a6.css.gz" type="text/css">'
+ out = u'<link rel="stylesheet" href="/media/CACHE/css/5b231a62e9a6.css.gz" type="text/css">'
self.assertEqual(out, render(template, context))
@@ -383,8 +385,8 @@ def test_offline(self):
count, result = CompressCommand().compress()
self.assertEqual(2, count)
self.assertEqual(result, [
- u'<link rel="stylesheet" href="/media/cache/css/a55e1cf95000.css" type="text/css">\n',
- u'<script type="text/javascript" src="/media/cache/js/bf53fa5b13e2.js" charset="utf-8"></script>',
+ u'<link rel="stylesheet" href="/media/CACHE/css/a55e1cf95000.css" type="text/css">\n',
+ u'<script type="text/javascript" src="/media/CACHE/js/bf53fa5b13e2.js" charset="utf-8"></script>',
])
def test_offline_with_context(self):
@@ -395,7 +397,7 @@ def test_offline_with_context(self):
count, result = CompressCommand().compress()
self.assertEqual(2, count)
self.assertEqual(result, [
- u'<link rel="stylesheet" href="/media/cache/css/8a2405e029de.css" type="text/css">\n',
- u'<script type="text/javascript" src="/media/cache/js/bf53fa5b13e2.js" charset="utf-8"></script>',
+ u'<link rel="stylesheet" href="/media/CACHE/css/8a2405e029de.css" type="text/css">\n',
+ u'<script type="text/javascript" src="/media/CACHE/js/bf53fa5b13e2.js" charset="utf-8"></script>',
])
settings.COMPRESS_OFFLINE_CONTEXT = self._old_offline_context
View
238 docs/_theme/compressor/static/compressor.css_t
@@ -1,238 +0,0 @@
-/**
- * Sphinx stylesheet -- default theme
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-@import url("basic.css");
-
-/* -- page layout ----------------------------------------------------------- */
-
-body {
- font-family: Arial, sans-serif;
- font-size: 100%;
- background-color: #111111;
- color: #555555;
- margin: 0;
- padding: 0;
-}
-
-div.documentwrapper {
- float: left;
- width: 100%;
-}
-
-div.bodywrapper {
- margin: 0 0 0 300px;
-}
-
-hr{
- border: 1px solid #B1B4B6;
-}
-
-div.document {
- background-color: #fafafa;
-}
-
-div.body {
- background-color: #ffffff;
- color: #3E4349;
- padding: 1em 30px 30px 30px;
- font-size: 0.9em;
-}
-
-div.footer {
- color: #555;
- width: 100%;
- padding: 13px 0;
- text-align: center;
- font-size: 75%;
-}
-
-div.footer a {
- color: #444444;
-}
-
-div.related {
- background-color: #6b2a1e;
- color: #ffffff;
- font: 1.2em/40px "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
-}
-
-span.pre {
- font: 0.7em Monaco, "Courier New", Courier, mono;
-}
-
-div.related a {
- color: #fff4eb;
-}
-
-div.related .right {
- font-size: 0.9em;
-}
-
-div.sphinxsidebar {
- font-size: 0.9em;
- line-height: 1.5em;
- width: 300px
-}
-
-div.sphinxsidebarwrapper{
- padding: 20px 0;
-}
-
-div.sphinxsidebar h3,
-div.sphinxsidebar h4 {
- font-family: Arial, sans-serif;
- color: #222222;
- font-size: 1.2em;
- font-weight: bold;
- margin: 0;
- padding: 5px 10px;
- text-shadow: 1px 1px 0 white
-}
-
-div.sphinxsidebar h3 a {
- color: #444444;
-}
-
-div.sphinxsidebar p {
- color: #888888;
- padding: 5px 20px;
- margin: 0.5em 0px;
-}
-
-div.sphinxsidebar p.topless {
-}
-
-div.sphinxsidebar ul {
- margin: 10px 10px 10px 20px;
- padding: 0;
- color: #000000;
-}
-
-div.sphinxsidebar a {
- color: #444444;
-}
-
-div.sphinxsidebar a:hover {
- color: #E32E00;
-}
-
-div.sphinxsidebar input {
- border: 1px solid #cccccc;
- font-family: sans-serif;
- font-size: 1.1em;
- padding: 0.15em 0.3em;
-}
-
-div.sphinxsidebar input[type=text]{
- margin-left: 20px;
-}
-
-/* -- body styles ----------------------------------------------------------- */
-
-a {
- color: #005B81;
- text-decoration: none;
-}
-
-a:hover {
- color: #E32E00;
-}
-
-div.body h1,
-div.body h2,
-div.body h3,
-div.body h4,
-div.body h5,
-div.body h6 {
- font-family: Arial, sans-serif;
- font-weight: normal;
- color: #212224;
- margin: 30px 0px 10px 0px;
- padding: 5px 0 5px 0px;
- text-shadow: 0px 1px 0 white;
- border-bottom: 1px solid #C8D5E3;
-}
-
-div.body h1 { margin-top: 0; font-size: 200%; }
-div.body h2 { font-size: 150%; }
-div.body h3 { font-size: 120%; }
-div.body h4 { font-size: 110%; }
-div.body h5 { font-size: 100%; }
-div.body h6 { font-size: 100%; }
-
-a.headerlink {
- color: #c60f0f;
- font-size: 0.8em;
- padding: 0 4px 0 4px;
- text-decoration: none;
-}
-
-a.headerlink:hover {
- background-color: #c60f0f;
- color: white;
-}
-
-div.body p, div.body dd, div.body li {
- line-height: 1.8em;
-}
-
-div.admonition p.admonition-title + p {
- display: inline;
-}
-
-div.highlight{
- background-color: white;
-}
-
-div.note {
- background-color: #eeeeee;
- border: 1px solid #cccccc;
-}
-
-div.seealso {
- background-color: #ffffcc;
- border: 1px solid #ffff66;
-}
-
-div.topic {
- background-color: #fafafa;
- border-width: 0;
-}
-
-div.warning {
- background-color: #ffe4e4;
- border: 1px solid #ff6666;
-}
-
-p.admonition-title {
- display: inline;
-}
-
-p.admonition-title:after {
- content: ":";
-}
-
-pre {
- padding: 4px 6px;
- background-color: #fff;
- border: 1px solid #ccc;
- color: #222222;
- margin: 1.5em 0 1.5em 0;
- border-right-color: #e3e3e3;
- border-bottom-color: #e3e3e3;
- line-height: 1.5em;
- font-size: 1.1em;
-}
-
-tt {
- color: #222222;
- padding: 1px 2px;
- font-size: 1.2em;
- font-family: monospace;
-}
-
-#table-of-contents ul {
- padding-left: 2em;
-}
View
3  docs/_theme/compressor/theme.conf
@@ -1,3 +0,0 @@
-[theme]
-inherit = basic
-stylesheet = compressor.css
View
6 docs/conf.py
@@ -50,7 +50,7 @@
# The short X.Y version.
version = '0.6'
# The full version, including alpha/beta/rc tags.
-release = '0.6b2'
+release = '0.6b3'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -91,7 +91,7 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'compressor'
+html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -99,7 +99,7 @@
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-html_theme_path = ['_theme']
+# html_theme_path = ['_theme']
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
View
134 docs/index.txt
@@ -3,8 +3,36 @@ Django compressor
Compresses linked and inline JavaScript or CSS into a single cached file.
-Syntax
-------
+Installation
+------------
+
+* Install django_compressor with your favorite Python package manager::
+
+ pip install django_compressor
+
+* Add ``'compressor'`` to your ``INSTALLED_APPS`` setting::
+
+ INSTALLED_APPS = (
+ # other apps
+ "compressor",
+ )
+
+* See the list of settings_ to modify django_compressor's default behaviour.
+
+* In case you use Django 1.3's staticfiles_ contrib app (or its standalone
+ clone django-staticfiles_) you have to add django_compressor's file finder
+ to the ``STATICFILES_FINDERS`` setting::
+
+ STATICFILES_FINDERS = (
+ # other finders..
+ 'compressor.finders.CompressorFinder',
+ )
+
+.. _staticfiles: http://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/
+.. _django-staticfiles: http://pypi.python.org/pypi/django-staticfiles
+
+Usage
+-----
.. code-block:: django
@@ -14,7 +42,7 @@ Syntax
{% endcompress %}
Examples
---------
+^^^^^^^^
.. code-block:: django
@@ -30,7 +58,7 @@ Which would be rendered something like:
.. code-block:: django
- <link rel="stylesheet" href="/static/cache/css/f7c661b7a124.css" type="text/css" charset="utf-8">
+ <link rel="stylesheet" href="/static/CACHE/css/f7c661b7a124.css" type="text/css" charset="utf-8">
or:
@@ -47,10 +75,11 @@ Which would be rendered something like:
.. code-block:: django
- <script type="text/javascript" src="/static/cache/js/3f33b9146e12.js" charset="utf-8"></script>
+ <script type="text/javascript" src="/static/CACHE/js/3f33b9146e12.js" charset="utf-8"></script>
-Linked files must be accesible via COMPRESS_URL_. If DEBUG is true off-site
-files will throw exceptions. If DEBUG is false they will be silently stripped.
+Linked files must be accesible via COMPRESS_URL_. If DEBUG is ``True``,
+off-site files will throw exceptions. If DEBUG is ``False`` they will be
+silently stripped.
If COMPRESS is ``False`` (defaults to the opposite of DEBUG) the ``compress``
template tag simply returns exactly what it was given, to ease development.
@@ -65,6 +94,87 @@ template tag simply returns exactly what it was given, to ease development.
.. _memcached: http://memcached.org/
.. _caching documentation: http://docs.djangoproject.com/en/1.2/topics/cache/#memcached
+Remote storages
+---------------
+
+In some cases it's useful to use a CDN_ for serving static files such as
+those generated by django_compressor. Due to the way django_compressor
+processes files, it requires the files to be processed (in the
+``{% compress %}`` block) to be available in a local file system cache.
+
+django_compressor provides hooks to automatically have compressed files
+pushed to a remote storage backend. Simply use set the COMPRESS_STORAGE_
+setting to a storage backend that saves the result to a remote service.
+
+So assuming your CDN is `Amazon S3`_, you can use the boto_ storage backend
+from the 3rd party app `django-storages`_. Some required settings are::
+
+ AWS_ACCESS_KEY_ID = 'XXXXXXXXXXXXXXXXXXXXX'
+ AWS_SECRET_ACCESS_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
+ AWS_STORAGE_BUCKET_NAME = 'compressor-test'
+
+Next, you need to specify the new CDN base URL and update the URLs to the
+files in your templates which you want to compress::
+
+ COMPRESS_URL = "http://compressor-test.s3.amazon.com/"
+
+.. note::
+
+ For staticfiles just set ``STATIC_URL = COMPRESS_URL``
+
+The storage backend to save the compressed files needs to be changed, too::
+
+ COMPRESS_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
+
+staticfiles
+^^^^^^^^^^^
+
+If you are using Django 1.3's staticfiles_ contrib app or the standalone
+app django-staticfiles_, you'll need to use a temporary filesystem cache
+for django_compressor to know which files to compress. Since staticfiles
+provides a management command to collect static files from various
+locations which uses a storage backend, this is where both apps can be
+integrated.
+
+First, make sure the COMPRESS_ROOT_ and STATIC_ROOT_ settings are equal
+since both apps need to look at the same directories when to do their job.
+
+Secondly, you need to create a subclass of the remote storage backend
+you want to use; below is an example of the boto S3 storage backend
+from django-storages::
+
+ from django.core.files.storage import get_storage_class
+ from storages.backends.s3boto import S3BotoStorage
+
+ class CachedS3BotoStorage(S3BotoStorage):
+ """
+ S3 storage backend that saves the files locally, too.
+ """
+ def __init__(self, *args, **kwargs):
+ super(CachedS3BotoStorage, self).__init__(*args, **kwargs)
+ self.local_storage = get_storage_class(
+ "compressor.storage.CompressorFileStorage")()
+
+ def save(self, name, content):
+ name = super(CachedS3BotoStorage, self).save(name, content)
+ self.local_storage._save(name, content)
+ return name
+
+Set your COMPRESS_STORAGE_ and STATICFILES_STORAGE_ settings to the
+dotted path of your custom cached storage backend,
+e.g. ``'mysite.storage.CachedS3BotoStorage'``.
+
+To have Django correctly render the URLs to your static files, set the
+``STATIC_URL`` setting to the same value as COMPRESS_URL_ (e.g.
+``"http://compressor-test.s3.amazon.com/"``).
+
+.. _CDN: http://en.wikipedia.org/wiki/Content_delivery_network
+.. _Amazon S3: https://s3.amazonaws.com/
+.. _boto: http://boto.cloudhackers.com/
+.. _django-storages: http://code.welldev.org/django-storages/
+.. _STATIC_ROOT: http://docs.djangoproject.com/en/dev/ref/settings/#std:setting-STATIC_ROOT
+.. _STATICFILES_STORAGE: http://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_STORAGE
+
CSS Notes
---------
@@ -137,7 +247,7 @@ will be written to.
.. note::
This setting defaults to ``MEDIA_URL`` in case ``STATIC_URL``
- is not given, e.g. on older Django versions (<1.3).
+ is not given or empty, e.g. on older Django versions (<1.3).
COMPRESS_ROOT
^^^^^^^^^^^^^
@@ -145,7 +255,8 @@ COMPRESS_ROOT
:Default: ``STATIC_ROOT`` (``MEDIA_ROOT`` for older Django versions)
Controls the absolute file path that linked static will be read from and
-compressed static will be written to.
+compressed static will be written to when using the default COMPRESS_STORAGE_
+``compressor.storage.CompressorFileStorage``.
.. note::
@@ -155,7 +266,7 @@ compressed static will be written to.
COMPRESS_OUTPUT_DIR
^^^^^^^^^^^^^^^^^^^
-:Default: ``'cache'``
+:Default: ``'CACHE'``
Controls the directory inside COMPRESS_ROOT_ that compressed files will
be written to.
@@ -226,9 +337,6 @@ COMPRESS_REBUILD_TIMEOUT
The period of time after which the compressed files are rebuilt even if
no file changes are detected.
-This is also used by the ``compress`` management command which pre-compresses
-the contents of ``{% compress %}`` template tags in the cache.
-
COMPRESS_MINT_DELAY
^^^^^^^^^^^^^^^^^^^
Please sign in to comment.
Something went wrong with that request. Please try again.