views:

228

answers:

5

What’s the best way to keep related files together in Django?

In addition to our HTML templates, most views have at least one additional JavaScript file, and possibly an additional CSS file. For example:

  • item_detail.html
  • item_detail.js
  • item_detail.css

We want to keep these files side-by-side if possible, so we don't have to look in two or three directories to find them.

Update: I do know that it’s dumb to defeat caching and that’s not what I’m asking. Each page loads several JavaScript and CSS items that are properly cached. For example:

<!-- at top of file -->
<link rel="stylesheet" href="/master/css/site-main.css">

<!-- at bottom of file -->
<script type="text/javascript" src="/master/js/jquery.js"></script>
<script type="text/javascript" src="/master/js/site-main.js"></script>

That part is fine.

In addition to this, each page loads page-specific JavaScript and CSS:

<link rel="stylesheet" href="/static/css/widgets/item_detail.css">
<script type="text/javascript" src="/static/js/widgets/item_detail.js"></script>

In this example, item_detail.js would have event handlers that are needed on the item detail page (only).

Unfortunately this means that I now have several parallel directory structures for this view:

  • my_site
    • widgets
      • item_detail.htmlThis is the view
    • static
      • css
        • item_detail.cssThis is the view-specific CSS
      • js
        • item_detail.jsThis is the view-specific JavaScript

What I want is this:

  • my_site
    • widgets
      • item_detail.htmlThis is the view
      • item_detail.cssThis is the view-specific CSS
      • item_detail.jsThis is the view-specific JavaScript

Due to the way views work in Django, it’s not clear to me that this is possible.

A: 

I agree with freiksenet. A solution to the problem he adresses could be aggregating the various css and js files. The whole site then uses just one css and one js file. The first load would be higher, yes, but a big part of the speed of a site is in downloading files, and if caching is done right, aggregation of these files helps imho.

I unfortunately don't have an answer to your main question.

Niels Bom
Thanks. I like this idea for optimizing deployment, but our developers would still have to bounce all around the project to get to related files during development. We do something similar with PHP and Smarty (keep related files in one place) and it’s been a productivity boost. Django is new for us.
Nate
I'd think that file aggregation and putting certain files in the same directory (as you're suggesting) aren't mutually exclusive.(disclosure: I have no knowledge of Django)
Niels Bom
Unfortunately, you can’t put JavaScript and CSS in the same directory as your HTML templates in Django (during development, as far as I know), which is the inconvenience I’d like to solve.
Nate
A: 

I keep javascript in files separated by function and combine them into a single minified js file with a pre-commit hook (right after the tests run).

for example: I have several jquery-ui dialogs on the site I'm currently working on. Each dialog's functionality is broken off into it's own js file for maintainability. And all the needed js files are "included" on the development pages using a short base.js file like so:

function include(filename) {
    document.write(unescape("%3Cscript src='" + filename + "' type='text/javascript'%3E%3C/script%3E"));
}

// include-js (external)
include('/site_media/jquery-plugin1.js');
include('/site_media/js-sources/dialog1.js');

my pre-commit hook does a regex on this file...

include\('/site_media/(.*)'\);

and feeds all the files into YUI compressor.

So I guess the answer to your question is... I put them wherever makes sense to me logically, because on the live site, it'll all be in the minified JS file(s) anyway

Jiaaro
Okay, now we’re getting somewhere. When you say “I put them wherever makes sense to me logically”—how can you do this in Django during development? The directory where your view is stored is not accessible from the browser. Instead I've got to map a URL to a different director(y|ies) where the `.js` and `.css` files are stored. So as a developer I have to jump between at least 3 different directories to edit one page.
Nate
I generally keep all the css/javascript in a single "site_media" folder and just give them names appropriate to the page they belong to. I keep the site_media folder open pretty much all the time
Jiaaro
+1  A: 

If you are just organizing stuff for development, you can symlink you template dir with all template, css and js files to directory you are serving static files too.

So from your example: add my_site/widgets to Django TEMPLATE_DIRS config and cp -s my_site/widgets to directory you have your static files in.

This is dirty hack and, please, don't use it in production as it is very insecure IMHO. But if you want to have neatly organized project in development stage - then I see this as one possible solution.

And also consider that this might give you loads of headache when you move from development to production as stuff WILL fail.

freiksenet
Very interesting. As you say, it seems fragile, but is going in the right direction. I also suspect it could be problematic with Subversion. Modding this up because this is the type of answer I’m looking for, even if this specific solution has problems.
Nate
If you are using apache as static server you can also block .html files in .htaccess. I still won't use this kind of setup in production, but this way it is safer.
freiksenet
A: 

You don't want to have your templates available as static files -- they may contain sensitive information or details about the page's implementation which are not appropriate for the public to see.

CSS and JS do not have to be segregated into separate directories -- simply place them in the static/ directory.

  • my_site/
    • widgets/
      • item_detail.html
    • static/
      • item_detail.css
      • item_detail.js
John Millikin
A: 

One approach I’m testing:

  • my_site/
    • widgets/
      • item_detail.html
      • item_detail.css
      • item_detail.js

These are not shared statically. Instead, in the HTML template:

<script type="text/javascript" charset="utf-8">
    {% include "widgets/item_detail.js" %}    
</script>

(Similar code for CSS.) I would only do this for page-specific JavaScript and CSS, not site-wide stuff that can benefit from caching.

This dumps the actual JavaScript and/or CSS right into the template, yet allows me to keep them in separate files for development purposes. This is nice, development-wise but defeats some JavaScript and CSS caching, but only for page-level stuff that’s not re-used on any other page.

Nate
That would mean that you have js and css file inside your html, so they are uncacheable. But this could work for dev.
freiksenet
But only page-specific .js and .css. Site-wide .js and .css still cacheable. But I’m probably going to give up on this whole idea and try to do things the standard, Django way. Multiple directories.
Nate
That's definitely the best way. The time you will spend with deployment problems will at least match time you will save with good organization.
freiksenet