Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Separation of Static Files & Assets with Django Compressor & Usage of collectstatic

I'm having a really hard time getting my head around the use of django-compressor.

Here's what I'm attempting to accomplish:

Separation of Static Files & Assets (LESS, Coffeescript)

I would like to separate my LESS CSS and Coffeescript files into an assets directory

e.g.

    app
    └── assets
        ├── coffee
        │   └── script.coffee
        └── less
            └── style.less

Leaving static assets such as images in my static directory

e.g.

    app
    └── static
        ├── hello.txt
        └── photo.jpg

To do this, I've added the assets path to my STATICFILES_DIRS variable to allow django-compressor to find the files (which works as expected). Is this the correct approach? I have been trying to find an independent load path dedicated to django-compressor but didn't have any luck as I don't intend for these assets to be served as statics.

Collection of Files for Production Deployment

For deploying to production, I would then like the compiled CSS & JS files along with other media in my app/static directory (e.g. images and so on) to be collected to an app/static-prod directory. But this doesn't work out so well because the assets are also collected when using the collectstatic command.

e.g.

(django-cpython)fots@fotsies-ubprecise-01:~/django_learning$ ./manage.py collectstatic --noinput
Copying '/home/fots/django_learning/app/assets/less/style.less'
Copying '/home/fots/django_learning/app/assets/less/import.less'
Copying '/home/fots/django_learning/app/assets/coffee/script.coffee'
Copying '/home/fots/django_learning/app/static/photo.jpg'
Copying '/home/fots/django_learning/app/static/hello.txt'

5 static files copied.

Using the ./manage.py compress command only takes tare of my compiled files, not photo.jpg or hello.txt in this example.

The only possible way I've found to do this is using the --ignore flag with collectstatic

e.g.

(django-cpython)fots@fotsies-ubprecise-01:~/django_learning$ ./manage.py collectstatic --noinput --ignore=less --ignore=coffee
Copying '/home/fots/django_learning/app/static/photo.jpg'
Copying '/home/fots/django_learning/app/static/hello.txt'

2 static files copied.

I've also messed around with the COMPRESS_ROOT and COMPRESS_URL configuration variables but these only cause further trouble. Changing COMPRESS_ROOT resolves the collectstatic issue but now when using the compress command, the generated files end up in a different location to the static files.

These solutions hardly seem elegant. Is there a better way to do this? I feel like I'm missing something.

Thanks in advance for any help :)

like image 856
Fotis Gimian Avatar asked Jan 14 '13 08:01

Fotis Gimian


1 Answers

I thought I'd provide the best solution I have found so far but please feel free to suggest better alternatives.

The biggest issue preventing my requirement is the fact that django-compressor uses the same path for its finder and output. The best solution I've found is as follows.

Creating a custom finder

We first create a custom finder based on a new setting I call COMPRESS_SOURCE_ROOT

from compressor.storage import CompressorFileStorage
from compressor.finders import CompressorFinder
from compressor.conf import settings


class CompressorFileAltStorage(CompressorFileStorage):
    """
    This alternative django-compressor storage class is utilised
    specifically for CompressorAltFinder which allows an independent
    find path.

    The default for ``location`` is ``COMPRESS_SOURCE_ROOT``.
    """
    def __init__(self, location=None, base_url=None, *args, **kwargs):
        if location is None:
            location = settings.COMPRESS_SOURCE_ROOT
        # The base_url is not used by the Finder class so it's irrelevant
        base_url = None
        super(CompressorFileAltStorage, self).__init__(location, base_url,
                                                       *args, **kwargs)

class CompressorAltFinder(CompressorFinder):
    """
    A staticfiles finder that looks in COMPRESS_SOURCE_ROOT
    for compressed files, to be used during development
    with staticfiles development file server or during
    deployment.
    """
    storage = CompressorFileAltStorage

Using this new finder

Simply add this finder to your STATICFILES_FINDERS setting in addition to the usual 'compressor.finders.CompressorFinder'

e.g.

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
    'mycomp.CompressorAltFinder',
    'compressor.finders.CompressorFinder',
)

And now set up a new setting called COMPRESS_SOURCE_ROOT

e.g.

COMPRESS_SOURCE_ROOT = os.path.join(APP_DIR, 'assets')

I've also set my STATIC_ROOT too

STATIC_ROOT = os.path.join(APP_DIR, 'static-prod')

Testing the Solution in Development

I specifically tested my LESS source code compilation

(django-cpython)fots@fotsies-ubprecise-01:~/django_learning$ tree app/assets
app/assets
├── coffee
│   └── script.coffee
└── less
    ├── import.less
    └── style.less

With template tags

{% compress css %}
  <link rel="stylesheet" type="text/less"
        href="{{ STATIC_URL }}less/style.less" />
{% endcompress %}

This is read from the assets directory successfully and updated when I change the files.

The output is placed in the static-prod directory:

(django-cpython)fots@fotsies-ubprecise-01:~/django_learning$ tree app/static-prod/
app/static-prod/
└── CACHE
    ├── css
    │   ├── style.5abda32cfef7.css
    │   └── style.6ca1a3d99280.css
    └── js
        └── script.8cb4f955df19.js

3 directories, 3 files

Testing the Solution for Production

For your reference, here's what my static directory looks like

(django-cpython)fots@fotsies-ubprecise-01:~/django_learning$ tree app/static
app/static
├── hello.txt
└── photo.jpg

0 directories, 2 files

So here we go

(django-cpython)fots@fotsies-ubprecise-01:~/django_learning$ rm -rf app/static-prod
(django-cpython)fots@fotsies-ubprecise-01:~/django_learning$ ./manage.py collectstatic --noinput
Copying '/home/fots/django_learning/app/static/photo.jpg'
Copying '/home/fots/django_learning/app/static/hello.txt'

2 static files copied.
(django-cpython)fots@fotsies-ubprecise-01:~/django_learning$ ./manage.py compress
Found 'compress' tags in:
        /home/fots/django_learning/app/templates/layout.html
Compressing... done
Compressed 2 block(s) from 1 template(s).
(django-cpython)fots@fotsies-ubprecise-01:~/django_learning$ tree app/static-prod
app/static-prod
├── CACHE
│   ├── css
│   │   └── 5abda32cfef7.css
│   ├── js
│   │   └── 3b9d1c08d2c5.js
│   └── manifest.json
├── hello.txt
└── photo.jpg

3 directories, 5 files

I then ran the webserver as follows and confirmed that the site was operational

./manage.py runserver 0.0.0.0:8000 --insecure

Hope this helps somebody out there :)

like image 113
Fotis Gimian Avatar answered Oct 05 '22 14:10

Fotis Gimian