I'm using Python 3.5 and Django 1.10 to run a development server:
./manage.py runserver 0.0.0.0:8000
In my settings.py
I have:
DEBUG = True
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
And an app
directory, with a static
subdirectory for its static files:
proj/
proj/
...
app/
static/
a.txt
...
static/
b.txt
Pretty standard.
However: Django doesn't serve the STATIC_ROOT
when DEBUG = True
. It returns app/static/a.txt
for /static/a.txt
alright, but not static/b.txt
for /static/b.txt
.
Changing settings.py
to read:
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
Works - but then I have to comment out STATIC_ROOT
(otherwise Django complains it can't be in STATICFILES_DIRS
).
Now, I can't just "use a different external static directory", e.g. static2
, because I'm using django-sass-processor
, which compiles .sass
files into .css
files, and puts these .css
files in the STATIC_ROOT
(which, as I've said, is inaccessible).
Things I've tried:
Settings up NGINX to serve that directory (like in a production environment). Works, but there just has to be another way.
Configuring django-sass-processor
to write the .css
files into said "different external static directory", e.g. static2
, and including it in STATICFILES_DIRS
. Again, works, but it just can't be that complicated!
Manually adding static files URLs in urls.py
:
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
This one was quite a trip, so I thought I'd share it to save other people the trouble: it turns out that Django does that anyway, and actually overwrites my URLs - but it includes, as I've said, only my apps' static directories and those in STATICFILES_DIRS
.
I even changed DEBUG
to False
and removed the if
- but that didn't work as well, because then the django.conf.urls.static.static
function actually returns an empty list. So, I implemented it myself using django.views.static.serve
, and it finally worked, but again - it doesn't make sense I have to turn off debugging and manually implement serving static file.
Update
If you're working with django-sass-processor
and running into similar problems, they've actually provided a solution I just noticed in their documentation: a special static finder you can add in your settings.py
like so:
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'sass_processor.finders.CssFinder',
]
(The first two are Django's default finders, so when you override this configuration you should include them manually).
But even now, for anything other than .css
files, the STATIC_ROOT
is actually the only static directory that is inaccessible via /static/
, which I find pretty odd. So, I'd still like to solve (or at least understand...) it.
Learning programming: Why does DEBUG=False setting make my Django Static Files Access fail? Because the Django development server does not serve static files. You need to have a web server like nginx or Apache to serve your static files.
At first glance it seems very strange that Django doesn't serve files from STATIC_ROOT
, but it makes sense when you consider the workflow Django intends for static files. Django expects that you bundle static files alongside apps and you save project-level static files in a separate directory that is checked into version control. Then, when you run manage.py collectstatic
the STATICFILES_FINDERS
are used to gather up all the files into a single directory (which should not be in version control) so they can be deployed to AWS S3 or whatever.
So the staticfiles finders have two jobs:
If you were able to include STATIC_ROOT
in your STATICFILES_DIRS
then the collectstatic command would probably get stuck in a loop. Also, the Django developers don't intend for you to save files in STATIC_ROOT
since it shouldn't be checked into version control.
However, there's times when you actually do want to serve files from STATIC_ROOT
. In my case, I have a Celery task that creates thumbnails of uploaded images and saves them to the static files storage. In production that ends up saving on AWS S3 where it can be served.
So, if you have a valid use case for serving files from STATIC_ROOT
just define your own file finder and add it's path to STATICFILES_FINDERS
:
from django.contrib.staticfiles.finders import BaseFinder
from django.contrib.staticfiles.storage import staticfiles_storage
class StaticRootFinder(BaseFinder):
"""
For debug mode only. Serves files from STATIC_ROOT.
"""
def find(self, path, all=False):
full_path = staticfiles_storage.path(path)
if staticfiles_storage.exists(full_path):
return [full_path] if all else full_path
return []
def list(self, ignore_patterns):
return iter(())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With