2

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'm running the 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 put the Javascript and CSS? I've tried it in a bunch of places, including myapp/, templates/ and mysite/, but none seem to work.

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 that the serve() line is the cause of errors like:

TypeError at /admin/auth/
'tuple' object is not callable

Just to round off the rampant flailing, 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's still not working:

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 a url like http://127.0.0.1:8000/media/sprintf.js, I get:

Page not found: /media/sprintf.js
Nick Heiner
  • 119,074
  • 188
  • 476
  • 699
  • If you turn on DEBUG, the 404 page should have something like: "/home/....../site_media/sprintf.js" does not exist, then you can see if the system path is correct. – Dingle May 02 '10 at 01:42
  • Perhaps this could be of help: https://stackoverflow.com/questions/14799835/django-static-files-results-in-404/14800489#14800489 – Henrik Andersson Jul 31 '14 at 23:56

8 Answers8

4

But does that /media/ global directory exist? And have you placed in there a scripts subdirectories with the scripts you want to serve from there? What about the /scripts/... url from which you want to serve JQuery.js -- that doesn't seem to be served anywhere from your urls.py. If you (for whatever reason) want to serve scripts (or any other statically served file) from several different URL paths, all of those URL paths need to be matched in urls.py with the static-serving -- or else, do the normal things and serve them all from the /media/... root URL, and map that media root to the dir where you actually keep these files (in their respective subdirs, typically).

Django's docs about static serving (for development only, since it's documented as

Using this method is inefficient and insecure. Do not use this in a production setting. Use this only for development.

so beware!-) seems pretty clear to me.

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • Well, then how else could you do this? Is there a method to embed things like javascript, css, and images (the things outlined [here](https://docs.djangoproject.com/en/dev/howto/static-files/)) other than a method which has been deemed **inefficient** and **insecure**? – michaelsnowden Jan 22 '14 at 23:18
2

You may want to use 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 don't play any role here.

Here are my settings for your reference. I put all static media files under 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 else where, just need to point 'document_root' to the correct path. Make sure comment out this url line for production deployment.

Dingle
  • 2,402
  • 19
  • 12
  • This isn't working for me. I am able to do `os.path.join(ROOT_PATH, 'site_media')` in the Django shell, and it works fine, and points to the location I want, but still nothing is being served. – Nick Heiner May 01 '10 at 13:22
  • You can use something like firebug to see what's the problem with loading your javascripts. Basically, you need to use an absolute path for 'document_root' such as /home/rosarch/..../site_media. I am just using settings.ROOT_PATH for convenience. – Dingle May 02 '10 at 01:27
1

Actually, you can put your Javascript files (and all your static content) anywhere you want. I mean, Django does not impose a standard on where to place them, after all they won't be handled by Django, they'll be served by the webserver.

Said that, It's a good idea to keep them somewhere close to the project's files. I'd recommend to keep them in a sibling folder to your Django code. Same with MEDIA_ROOT.

It is a good idea to decouple your static files from python files because now you can put them in totally separate folders in a production environment and easily give different access to static files and python code (say FTP access, or permissions).

Something to keep in mind is that the settings' MEDIA_ROOT is the place where user's media files (that is uploaded content) will be placed, these are not your static project files, these are whatever files your Django app uploads (avatars, attachments, etc).

Proposed 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 other responses recommendation on using Django's serve() function for development enviroment. Just make sure you add that url() to your urlpatterns under a settings.DEBUG is True conditional.

As for your templates, it's a good idea to use a context processor to send your static file's path to all your templates.

Jj.
  • 3,160
  • 25
  • 31
  • I believe Django already includes a context processor for your MEDIA_URL setting: django.core.context_processors.media – Zack May 01 '10 at 21:01
  • Yes, it does. although in the folder structure I use I differentiate MEDIA from STATIC, as MEDIA holds user's files and STATIC holds site's static content. then the MEDIA_URL context processor is good to refer to user's files, but I create a new STATIC_URL for the site's static content. – Jj. May 02 '10 at 02:06
0

I just remove the '^', "r'static/" instead of "r'^static/". It's works for me ,good luck.

url(r'static/(?P<path>.*)$', 'django.views.static.serve',
     { 'document_root': the_path }),
liamlee
  • 311
  • 2
  • 3
  • 10
0

I serve 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 handle the static directory when running in production to avoid any issues with Django's static serving mechanism.

Corey Porter
  • 1,309
  • 8
  • 9
0

For my development work, I use Django's built-in server, but I read the media files from the same directory as they would be in production (/srv/nginx/sitename/media/). So I clone the exact directory structure of my production server on my computer at home, letting me seamlessly push changes to production without having to change anything.

I keep two different settings.py files, though. My home settings.py file has my local database settings, a different MEDIA_URL setting, and DEBUG set to True. I use this in my URLs file to enable the server view for local media (since I don't run nginx on my home computer).

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 a template:

<link rel="stylesheet" href="{{ MEDIA_URL }}css/form.css" />{% endblock %}

Filesystems:

/srv/nginx/<sitename>
    /media  <-- MEDIA_ROOT/MEDIA_URL points to here
        /css
            base.css
            form.css
        /img
        /js

Oh, also: if that's a direct copy from your urls.py file, you forgot a comma after your serve view, that's causing your TypeError ;)

Zack
  • 2,274
  • 3
  • 24
  • 26
  • Indeed, that was the problem behind the TypeError. This still isn't working for me. What is the current working directory that `document_root` starts from? – Nick Heiner May 01 '10 at 13:29
  • I'm not sure if it starts from a directory, but I'd imagine your project root if I had to guess. The only scenario where you should be using the development server or serve view is working locally, and you should be able to make an absolute path on your local box. – Zack May 01 '10 at 17:15
  • Yeah, should... but somehow it isn't working. I updated the OP with my subsequent attempts. – Nick Heiner May 01 '10 at 20:22
  • Try changing `os.path.normpath` to `os.path.abspath`. I ran that line to see what ROOT_PATH would be and I got a result of '.' – Zack May 01 '10 at 21:04
  • Also, it's a good idea to use Django's MEDIA_URL and MEDIA_ROOT settings for this kind of stuff, add `django.core.context_processors.media` to your context processors and you'll have access to {{ MEDIA_URL }} in your templates. I'll update my answer with this. – Zack May 01 '10 at 21:06
  • MEDIA_URL and MEDIA_ROOT are mainly used for file uploading, I think. I usually don't mix them with my own static files. – Dingle May 02 '10 at 01:29
  • You need to specify upload_to with uploaded files, thus separating them from your files. I set that to something like `uploads/`. Many Django sites use their MEDIA_URL for serving static files, such as... Django. – Zack May 02 '10 at 01:57
0

This is a structure I use in a project separated into multiple apps. It's a good practice to adapt this structure right at the start -- you don't want global rearrangement when you need to add another app 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 excellent StaticMiddleware from django-annoying to serve files. settings.py:

import os
import annoying

MEDIA_ROOT = os.path.join(os.path.dirname(__file__), "media")
MIDDLEWARE_CLASSES = (
    'annoying.middlewares.StaticServe',
    #...
)
daniula
  • 6,898
  • 4
  • 32
  • 49
Alexander Lebedev
  • 5,968
  • 1
  • 20
  • 30
0

The error 404 occurs because MEDIA_ROOT requires absolute path, not relative. The server is trying to access /media in your filesystem, which is obviously 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/'
jweyrich
  • 31,198
  • 5
  • 66
  • 97