I'm having an odd issue when porting my Django site from dev server to Heroku. I know I'm not supposed to use django to directly serve the static files, but I'm just testing out an idea for now.
I've tried using:
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()
as well as:
from django.conf import settings
urlpatterns += patterns(
(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),)
but with either solution I my .css files get served just fine but my .png image files do not. Is there any reason these files would be different with respect to how Django and Heroku handle them?
It was the upper-lower case issue. It turns out the filename had one more cap letter than the reference in the html file... Always an issue when I move from Mac OS to case sensitive Unix.
Related
In production, the apache server can handle serving static files just fine. For testing on my local machine I'm using manage.py runserver.
It seems the django apps I have somehow inject some default search paths into this debug server. The browser url shows everything under /static/whatever, but those files are coming from all over the place. This is fine for testing but when moving to production I'll need them in the one path. Thankfully, manage.py collectstatic provides a handy method to copy everything to the one directory given by STATIC_ROOT in settings.py. I've set mine to os.path.join(BASE_DIR, 'static/') where BASE_DIR is where manage.py is.
Now I want to start adding my own stuff in static, but everything's still being hosted by these hidden search directories provided by apps under DEBUG=True. I've tried the following in urls.py:
from django.conf import settings
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
if settings.DEBUG:
urlpatterns += staticfiles_urlpatterns()
and
import re
from django.conf import settings
if settings.DEBUG:
static_url = re.escape(settings.STATIC_URL.lstrip('/'))
urlpatterns += patterns('',
(r'^%s(?P<path>.*)$' % static_url, 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),
)
Neither have worked.
I tried providing my static directory in STATICFILES_DIRS, but get the error ImproperlyConfigured: The STATICFILES_DIRS setting should not contain the STATIC_ROOT setting. So then I tried removing my STATIC_ROOT so the path was only given in STATICFILES_DIRS. Finally I can access my files in development (still with staticfiles_urlpatterns from above).
However, I'm pretty sure removing STATIC_ROOT is not the right way to go about it. For a start, I won't be able to run collectstatic after installing other apps without manually changing everything around again. How should I be configuring my static directory for development?
Also, is there a way to turn off hosting app specific static directories so I can make sure my single static is set up correctly (but still be in development mode)?
You're making this more complex than it needs to be. Include "static" in STATICFILES_DIRS as you are doing, for the project-level assets, but make STATIC_ROOT - ie the destination of the collectstatic command - something else, probably "staticfiles", and alias that directory to /static/ in Apache. Django will serve your assets from STATICFILES_DIRS automatically, without you even needing to add the urlpatterns.
OK, I completely missed the point here.
STATIC_ROOT is for collectstatic to pool all the static content for you. You don't add your files to here because it gets overwritten.
Now for production you can get your webserver to host the directory STATIC_ROOT and point STATIC_URL to the url it can be found through the webserver.
STATICFILES_DIRS allows you to add your own directories for collectstatic to search and pool to STATIC_ROOT. Then you can nicely separate static stuff for each of your apps and/or a common project static.
For dev, django expects everything to be in STATICFILES_DIRS and hosts that, not STATIC_ROOT because then there would be duplicates. This makes sense for larger projects because you want to be working on the per-app files, not some blob of stuff for a website.
I'm facing quite a strange issue with Django, my STATIC_URL is /static/ and I've got an app installed using pip as -e git+git://github.com/foo/bar.git#egg=bar which loads it into the virtualenv src folder.
Now, I'm trying to GET a static file related to this app as /static/bar/js/something.js and the src folder does have a bar/bar/static/bar/js/something.js file. Even if I findstatic bar/js/something.js it gives me a valid path to the file. However when I access it using the browser, I'm 301'd to /static/bar/js/something.js/ which 404s.
Why would this be happening?
Even poking around with staticfiles app, I was able to see that it recognizes my app as installed and that its static folder exists. However somehow the static files aren't being served.
Make sure that you have set up the django development server to actually server the static files for you.
urls.py
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
# ... the rest of your URLconf goes here ...
urlpatterns += staticfiles_urlpatterns()
Try using this urlpattern:
url( r'(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/path/to/file/'}),
Django 1.4 release notes state:
If you're implicitly relying on the path of the admin static files
within Django's source code, you'll need to update that path. The
files were moved from django/contrib/admin/media/ to
django/contrib/admin/static/admin/.
Could somebody explain how this is done exactly? Up to Django 1.3 we used ADMIN_MEDIA_PREFIX in settings.py, which is now deprecated. However, since we are developing all the time on our static files (js, css, ...), the staticfiles app is a rather annoying nogo for us. Calling collectstatic after each modification is a nightmare :-P
A pure Python/Django solution would be great. If that's impossible, we are using LighTPD as server and not Apache.
manage.py collectstatic is used when you deploy, during development you can have django serve your static and media files by adding this to your url.py:
from django.conf.urls.static import static
from django.conf import settings
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
...
...
if settings.DEBUG:
# add one of these for every non-static root you want to serve
urlpatterns+= static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# this take cares of static media (i.e. bundled in apps, and specified in settings)
urlpatterns+= staticfiles_urlpatterns()
This will also serve all the static files that are bundled with reusable apps. This avoids the real nightmare of having to add symlinks to your webserver root for every third party app per project!
Oops, I just found the solution in Django's new documentation:
https://docs.djangoproject.com/en/1.4/howto/deployment/wsgi/modwsgi/#serving-the-admin-files
Does anyone have a simple step-by-step tutorial about serving static files on a Django production app? I read the Django docs and it sounds really complicated... I'm trying to go the route of serving static files using a different server like lighttpd, nginx, or cherokee, but setting these up is all Greek to me. I downloaded lighttpd, tried to follow the instructions to install, and within a few seconds got an error. Missing this or that or whatnot... I'm not a UNIX whiz and I'm not very good at C/C++, so all this ./configure and MAKE install are gibberish to me... So I guess my immediate questions are:
Which server would you recommend to serve static files that's easy to install and easy to maintain?
Assuming I actually get the server up and running, then what? How do I tell Django to look for the files on that other server?
Again, anyone has step-by-step tutorials?
Thanks a lot!
Sorry, don't have a step by step tutorial. But here is a high level overview that might help:
You probably want to go with the Apache server ( http://httpd.apache.org/) This comes with most *nix distributions.
You then want to use mod python (or as the commenter pointed out mod_wsgi: http://docs.djangoproject.com/en/dev/howto/deployment/modwsgi/) to connect to Django : http://docs.djangoproject.com/en/dev/howto/deployment/modpython/?from=olddocs. Once you complete this step, Apache is now fronting for Django.
Next you want to collect the static files in your Django into one directory and point apache at that directory. You can do this using the the ./manage.py collectstatic if you used django.contrib.staticfiles (http://docs.djangoproject.com/en/dev/howto/static-files/.)
So the trick is you're not telling Django to delegate serving static files to a specific server. Rather you're telling httpd which urls are served via Django and what urls are static files.
Another way of saying this is that all requests come to the Apache web server. The webserver, according to the rules you specify in httpd.conf, will decide whether the request is for a static file or whether it is for a dynamic file generated by django. If it for a static file it will simply serve the file. If the request is for a dynamic file it will, via modpython, pass the request to Django.
Hope that helps.
Development
STATICFILES_DIRS should have all static directories inside which all static files are resident.
STATIC_URL should be /static/ if your files are in local machine otherwise put the base URL here e.g. http://example.com/.
INSTALLED_APPS should include django.contrib.staticfiles.
In the template, load the staticfiles module:
{% load staticfiles %}
<img src='{% static "images/test.png" %}' alt='img' />
Production
Add STATIC_ROOT that is used by Django to collect all static files from STATICFILES_DIRS to it.
Collect static files:
$ python manage.py collectstatic
Add the path to urls.py:
from . import settings
urlpatterns = patterns('',
..
url(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root':settings.STATIC_ROOT)}),)
More detailed articles are listed below:
http://blog.xjtian.com/post/52685286308/serving-static-files-in-django-more-complicated
http://agiliq.com/blog/2013/03/serving-static-files-in-django/
With the latest Django version like Django 3.2.6 I was having issues serving media and static files both in the dev and prod environment while DEBUG = False.
So I got around a solution that came from multiple stack overflow posts.
Import appropriate functions to urls.py
from django.urls import include, path, re_path
from django.views.static import serve
Define static URL pattern list to urls.py
static_urlpatterns = [
re_path(r"^media/(?P<path>.*)$", serve, {"document_root": settings.MEDIA_ROOT}),
re_path(r"^static/(?P<path>.*)$", serve, {"document_root": settings.STATIC_ROOT}),
]
Assuming your STATIC_ROOT and MEDIA_ROOT is already defined in settings.py file
Just include static_urlpatterns in urlpatterns
urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include(api_urlpatterns)),
path("", include(static_urlpatterns)),
]
Hope it works for you both in the dev and prod environment when DEBUG = FALSE. Thank you.
Updated for urls.py
the url(....) format doesn't work anymore in urls.py for Django 3.0.7.
you need to do then:
urls.py:
from django.conf import settings # to import static in deployment
from django.conf.urls.static import static # to import static in deployment
....
urlpatterns = [
....
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) # to import static in deployment
Reference: https://docs.djangoproject.com/en/3.0/howto/static-files/
Consider the following setup:
urls.py
if not settings.PRODUCTION:
urlpatterns += patterns('',
(r'^admin-media/(?P<path>.*)$', 'django.views.static.serve',{'document_root': settings.LOCAL_ADMIN_MEDIA_ROOT, 'show_indexes': True}),
(r'^media/(?P<path>.*)$', 'django.views.static.serve',{'document_root': settings.LOCAL_MEDIA_ROOT, 'show_indexes': True}),
)
settings.py
if not PRODUCTION:
ADMIN_MEDIA_PREFIX = '/admin-media/'
So when running on the local development server the media files should be served through the runserver, right? The media route is found, however "Permission denied" is returned for every request (but only one admin media, the regular media works fine).
So I did some checking into it. It turns out, if the ADMIN_MEDIA_PREFIX is set to the same value as the route...
(r'^admin-media/(?P<path>.*)$', 'django.views.static.serve', ... ),
ADMIN_MEDIA_PREFIX = '/admin-media/'
...then the runserver will always return "Permission denied."
However, if ADMIN_MEDIA_PREFIX is different than the route name...
(r'^admin-media/(?P<path>.*)$', 'django.views.static.serve', ... ),
ADMIN_MEDIA_PREFIX = '/non-sense-prefix/'
... then the files will be served (though I have to manually browse to be able to see them as all the media links are broken with http://localhost:8000/non-sense-prefix/whatever.jpg).
What's the deal here?
In the mean time I've solved the problem by a little hack to change directories...
(r'^admin-media/(?P<path>.*)$', 'django.views.static.serve', ... ),
ADMIN_MEDIA_PREFIX = '/admin-media/../admin-media/'
...but I would really rather configure this properly. It seems django is trying to be smart and do something on my behalf, but messing things up in the process. Any ideas?
EDIT --
I'm manually serving the admin media because I'm using grappelli which provides replacement for the admin templates/media.
If you're running Grappelli, you can set the admin media when using runserver by specifying the command line argument --adminmedia. Here is an example:
python manage.py runserver --adminmedia=/path/to/grappelli/media
Where /path/to/grappelli/media is the complete path to your Grappelli installation's media directory.
You don't need to specifically serve the admin media while using the development server - this should happen automatically.
I think it is simpler to just symlink in your local system to the django admin media, the same directory that you use in production, than to subject to a lot of if PRODUCTION within settings.
As Daniel rightly pointed out, django serves admin media by default. Anymore configuration is not required. So the problem is perhaps something different. Try chmod 777 on the templates directory, It may fix the problems.