Javascript with Django?
I know this has been asked before, but I'm having a hard time setting up JS on my Django web app even though I'm reading the documentation.
I am running Django dev server. My file structure looks like this:
mysite/ __init__.py MySiteDB manage.py settings.py urls.py myapp/ __init__.py admin.py models.py test.py views.py templates/ index.html
Where do I want to host Javascript and CSS? I've tried this in several places including myapp/
, templates/
and mysite/
, but none works.
From index.html :
<head>
<title>Degree Planner</title>
<script type="text/javascript" src="/scripts/JQuery.js"></script>
<script type="text/javascript" src="/media/scripts/sprintf.js"></script>
<script type="text/javascript" src="/media/scripts/clientside.js"></script>
</head>
From urls.py :
(r'^admin/', include(admin.site.urls)),
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': 'media'})
(r'^.*', 'mysite.myapp.views.index'),
I suspect the line serve()
is causing errors such as:
TypeError at /admin/auth/
'tuple' object is not callable
Just to round up the runaway movement, I changed these settings in settings.py :
MEDIA_ROOT = '/media/'
MEDIA_URL = 'http://127.0.0.1:8000/media'
UPDATE . I made some changes but it still doesn't work:
settings.py
ROOT_PATH = os.path.normpath(os.path.dirname(__file__))
urls.py
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': os.path.join(settings.ROOT_PATH, 'site_media')}),
index.html
<script type="text/javascript" src="/media/JQuery.js"></script>
<script type="text/javascript" src="/media/sprintf.js"></script>
<script type="text/javascript" src="/media/clientside.js"></script>
Filesystem
mysite/
site_media/
JQuery.js
sprintf.js
clientside.js
__init__.py
settings.py
manage.py
-- etc
myapp/
-- app files, etc
When I go to the url, for example http://127.0.0.1:8000/media/sprintf.js
, I get:
Page not found: /media/sprintf.js
a source to share
But does this global catalog exist /media/
? And have you put the scripts
scripts subdirectories in there that you want from there? How about the url /scripts/...
you want to serve JQuery.js
from that doesn't seem to be served anywhere from yours urls.py
. If you (for whatever reason) want to serve scripts (or any other statically served file) from several different urls, all of those url paths must be mapped in urls.py
to a static service - or else, do the normal stuff and serve them all from the root url /media/...
and map that media root to the directory where you actually store these files (usually in their respective subdirectories).
Django docs about static service (development only as it is documented as
Using this method is ineffective and unsafe . Don't use it in staging. Use this for development only.
so be careful! -) seems pretty clear to me.
a source to share
You can use the absolute path for 'document_root' in urls.py if you want to use the development server to serve static files. MEDIA_ROOT and MEDIA_URL play no role here.
Here are my settings for your reference. I put all static media in site_media /
mysite/ site_media/ css/ js/ images/ ...
in settings.py:
ROOT_PATH = os.path.normpath(os.path.dirname(__file__))
in urls.py:
url(r'^media/(?P<path>.*)$', "django.views.static.serve", {'document_root':
os.path.join(settings.ROOT_PATH, 'site_media')})
You can move static files to a different location, you just need to point "document_root" to the correct path. Be sure to comment out this URL line for your production deployment.
a source to share
Actually, you can put your Javascript files (and all your static content) anywhere. What I mean is that Django does not impose a standard on where to place them, because they will not be processed by Django, they will be served by the web server.
Said it's a good idea to keep them somewhere near the project files. I would recommend keeping them in the sisters folder in your Django code. It's the same with MEDIA_ROOT.
It's a good idea to separate your static files from python files, as you can now put them in completely separate folders in a production environment and easily provide different access to static files and python code (say FTP access or permissions).
Something to keep in mind is that the MEDIA_ROOT settings is where the custom media files will be placed (i.e. uploaded ), these are not your static project files, these are any files your Django download applications (avatars, attachments etc.).
Suggested folder structure:
mysite.com/
media/ - User media, this goes in settings.MEDIA_ROOT
static/ - This is your static content folder
css/
js/
images/
templates/
project/ - This is your Django project folder
__init__.py
manage.py
settings.py
myapp/
__init__.py
...files..py
See the recommendation of other answers for using Django feature serve()
for a development environment. Just make sure you add this one url()
to yours urlpatterns
under the symbol settings.DEBUG is True
.
As far as your templates are concerned, it's a good idea to use a context processor to send your static file path to all of your templates.
a source to share
I am serving javascript via static. So I have something in my urls.py like
(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': os.getenv('STATIC_DIR')})
So JS urls look like /static/js/blah.js
, CSS urls look like /static/css/blah.css
, etc. I have Apache handling a static directory when running in production to avoid any issues with Django's static serving engine.
a source to share
For my development, I am using the built-in Django server, but I am reading media from the same directory as in production (/ srv / nginx / sitename / media /). So I clone the exact directory structure of my production server on my computer at home, allowing me to seamlessly change production changes without changing anything.
I keep two different settings.py files. My home settings.py file has my local database settings, a different MEDIA_URL setting, and DEBUG is True. I use this in my url file to enable the server view for local media (since I am not running nginx on my home machine).
In urls.py:
if settings.DEBUG:
urlpatterns += patterns('',
(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT}),
)
From settings.py (note MEDIA_ROOT must be an absolute path):
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = '/srv/nginx/<sitename>/media/'
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = 'http://127.0.0.1:8000/media/'
TEMPLATE_CONTEXT_PROCESSORS = (
# I've taken out my other processors for this example
"django.core.context_processors.media",
)
In the template:
<link rel="stylesheet" href="{{ MEDIA_URL }}css/form.css" />{% endblock %}
File systems:
/srv/nginx/<sitename>
/media <-- MEDIA_ROOT/MEDIA_URL points to here
/css
base.css
form.css
/img
/js
Oh, also: if it's a direct copy from your urls.py file, you forgot the comma after your service submission, which caused your TypeError;)
a source to share
This is the structure I am using in a project split across multiple applications. It is good practice to adapt this structure at the very beginning - you don't need a global regrouping when you need to add another application to your project.
/media
favicon.ico
robots.txt
/upload # user uploaded files
/js # global js files like jQuery
/main_app
/js
/css
/img
/other_app
/js
/css
/img
Then I use the excellent StaticMiddleware
one django-annoying
for serving files. settings.py
import os
import annoying
MEDIA_ROOT = os.path.join(os.path.dirname(__file__), "media")
MIDDLEWARE_CLASSES = (
'annoying.middlewares.StaticServe',
#...
)
a source to share
The 404 error occurs because it MEDIA_ROOT
requires an absolute path, not a relative one. The server is trying to access /media
your filesystem, which is clearly not what you want.
Try this instead:
import os PROJECT_PATH = os.path.realpath(os.path.dirname(__file__)) MEDIA_ROOT = os.path.join(PROJECT_PATH, 'site_media') MEDIA_URL = '/media/'
a source to share