56 comments

[ 3.2 ms ] story [ 114 ms ] thread
Impressively long way around to avoid relying on Nginx or Apache. How does it perform in comparison?
That's an excellent question (and an idea for a follow-up blog post). In most cases I'd go with Django+Gunicorn+Nginx setup (as described here http://goodcode.io/blog/django-nginx-gunicorn/), with Nginx (or Apache) just being the reverse proxies and serving the static assets.

Django is still needed here if you want to have form processing (unless you use 3rd party service), and useful if you want to have templating (unless you want to use Jekyll, Hyde, or similar static-generator tools).

So, while Nginx/Apache would definitely speed up things, they're not enough. On the other hand, you can build a reasonably[0] fast "almost" static site with Django, and have it deployed on either your Linux server, or Heroku, or another PaaS.

[0] What's "reasonably fast"? my hunch tells me that the simple setup outlined here could take quite a beating (unless intentionally attacked with slowloris or similar attacks, or serving heavy static assets). It'll be fun to test it.

It's much easier (deployment/maintenance) using Gunicorn/uwsgi feeding into Nginx/Apache than using a module within Nginx/Apache

Especially with virtualenvs and such.

You can also setup a CloudFront deployment and point it to your app server as the origin. Fast and cheap way to serve static files without having to configure nginx/apache. Well...cheap as long as you don't need SSL.
One nice thing with Django is that you can separate out truly static files into your apps static folder, and configure nginx to serve the /static/ URL. Configure a `STATIC_ROOT` for your app, run:

    ./manage.py collectstatic
and you have nginx serving the truly static files while still allowing Django to manage your non-static assets.

This is how I run my site, and it works pretty darned well. Let nginx do the caching of static files, compression, and SSL management, letting Django just worry about its small domain of non-static files.

The one downside is that nginx will not necessairly detect when a static file has changed, requiring a bit of effort to ensure that new versions of a static file are puled, either through filename versioning, or `?1` on the end of your static URLs.

That's not unique to Django. You can always send static assets through the web server.
Absolutely. But, this being an article on Django, serving a combination of static and semi-static assets, commenting on this Django feature seemed appropriate.
IIRC, django-compressor will do that automatically.
If you're looking to django for static mostly for the templating engine and some build time python, I'd check out the excellent Cactus. Apparently there's a new downloadable mac app for it, which I've yet to try, but as a Django templater / designer, Cactus was always my goto for static sites.

https://github.com/koenbok/Cactus?source=c

The most interesting part to me is that there is no database. It had never occurred to me to use Django without one.
It's surprisingly easy, though I believe the tests expect one to be configured (I haven't checked precisely why, or if it can be configured not to expect a database).
I just configure it with SQLite in those cases. You can probably even specify ":memory:" for the DB location.
Also worth checking out is the Flask microframework. Setting up a simple static site with basic routing is ridiculously simple:

http://flask.pocoo.org/docs/quickstart/

I used it in conjunction with Bootstrap and Heroku to throw a personal site together in an evening, following this tutorial:

http://www.shea.io/lightweight-python-apps-with-flask-twitte...

Its not that difficult to set up a Django site once you have done it a couple of times.

What am I missing by not knowing Flask?

Flask doesn't make as many decisions for you as Django does. Some things that come bundled in Django are packages in Flask. A lot of the packages for Flask make fewer assumptions than similar packages for Django, which often makes using an uncommon data backend (ElasticSearch, Mongo, RethinkDB, Redis, etc) a little easier (you don't have to rewrite as much).
Flask (for python) and Sinatra[0] (for Ruby) are awesome. I just recently did two side projects using both. I use Webaction[1] for my hosting provider for "small" projects and getting Flask/Sinatra requires very little setup (just enough to make it fun). They also have one click installers for Rails/Django/etc. Super easy to setup if you're a dev noob like me.

[0] - http://www.sinatrarb.com/ [1] - http://www.webfaction.com/?affiliate=mbesto

I'm in the process of moving away from a static site for my website.

Simply put, a web interface is often more convenient so I can update things easier on the go, and it's good to have a place to host experiments too.

I have used various static site generators but none of them seemed to be significantly less work to get going than a small django app on heroku. Though I've been using Django for a few years, so there is simply no learning curve left.

Wait till your web site gets a ton of unexpected traffic.
What'll happen then? My Django-based blog handled hundreds of thousands of visits in a day without breaking a sweat. What it does is basically "fetch the whole page from memcached and serve it".
Having a dynamic "admin panel" does not mean you can't completely cache your user-facing pages.
And having HTML files on the filesystem doesn't mean you can't have an admin panel to update them with.
Do you have a Django plugin you'd like to suggest that does this?
Maybe something like Prose.io (Jekyll based). It gives you a very rudimentary interface to edit your posts for a static site.
(comment deleted)
I had the same problem (updating content), so I wrote a small script to download deltas from my Dropbox and parse them. Now I can edit my posts with vim:

http://www.stavros.io/posts/this-blog-is-dropbox-enabled/

That's a nice solution, though I've gone for a markdown admin widget instead.

This one if I remember correctly: https://github.com/timmyomahony/django-pagedown

Oooh, very nice, thanks for that!

One unintended (and great) side-effect of a Dropbox-hosted site is that you get mirrors for free (they all update together).

Don't do this. If you aren't using a database or processing forms, your life will be better if you learn jekyll and use it.
Until you need to add a bit of dynamicity, such as a contact form or something trivial, sadly.
There are plenty of form services you can drop on a static page. That is what you should do.
That assumes the only thing you'll need is a contact form, though. My site has various things, such as a page that shows a graph of my daily weight.
So... you're using a database? Great. Use Django.
I think his point is that it's quite likely you'll begin without a need for a database but later want to add some functionality requiring one. And at that point, you will have been better off starting with Django (or similar) as now you'll need to migrate everything over anyway.
That point is wrong. Setting up a Django deployment that won't fall over when you get traffic is more work than moving Jekyll templates into a Django install. Plus, if he'd started with Jekyll, he might have chosen to store his weights as a flat file that Jekyll could use to generate static charts.

Database-first thinking for content sites is just wrong. I've done it based on this same argument, and I've learned my lesson.

If you need a DB that's read only and updated infrequently you can just store the content in JSON files and parse them client side. Of course if you need to do writes it gets more complicated.
How will a static site fall over with Django? My page generation times are only a few ms, they're just fetched from cache, same as the static files.

The problem isn't showing the data, it's storing it. I have different computers gathering the data and deploying my site, so I would have to set up an elaborate solution, and I would still not be able to do A/B tests, sending email for new content, auto-Tweeting, etc.

The solution you've chosen is probably right for your situation. However, lots of people (including me not too long ago) create static sites in Django because they dream of making it more dynamic that way. That's usually a bad approach in my experience.
Something that I've been playing around with is hosting sites on S3. Then you can have a simple cron job that will just update an HTML or JSON data file at whatever frequency you want.

Nice way to keep the site static but add a bit of variability.

I don't understand why you need S3 for that. Can't you just as easily schedule an upload of updated files from your computer to your server?
It's other way around: with S3 you don't need your own server. KISS
Yea - it can work just as easily on your own server but the idea is that you don't have to worry about hosting at all and rely on S3 which is the most reliable AWS service.
If you dont want to generate static files with data for that, you can use the google docs json API to store the graph data and render that.
I tried going with that first, it was almost impossible. I never figured out how to do it.

Also, the bigger problem was, indeed, data storage, not display.

Its badly documented, but not impossible. I should write it up sometime.
You can also just deploy your static site to BitBalloon, then any contact form will start working and accepting form submissions. (Disclaimer, I'm the founder).

Link: https://www.bitballoon.com

I built a decently large static content site with a dynamic backend (http://yareallyarchive.com) on django.

With aggressive caching of all static pages it is fast as hell, and I love the django ecosystem. Adding search was as easy as dropping in django-haystack and adding like 5 lines of code. django-mptt has been brilliant for easily querying and manipulating comment trees.

It's possible to do small sites with django but it requires you to learn a lot of stuff you don't necessarily need. Flask is a better choice for small/nearly-static sites if you're not already familiar with a web framework.

This is exactly the method my company uses when one of the stories on our website is getting hammered by Reddit. I manually wget the rendered template, save it to a templates/static/ dir, and serve it directly.

Works like a charm.

Have you tried using django's built-in caching support?
We cache everything, but this simply takes care of not having to think about it. It might not be the best method, but it sure is the least troublesome/least cognitive load when things hit the fan.
Or you can use djangothis[1].

  $ pip install djangothis
  $ cat > views.py 
  from importd import d
  
  @d
  def hello(request):
     return d.HttpResponse("hello there")
  ^D
  $ djangothis
  Validating models...
  
  0 errors found
  February 18, 2014 - 16:43:31
  Django version 1.6.2, using settings None
  Starting development server at http://127.0.0.1:8000/
  Quit the server with CONTROL-C.
Any html files would be automatically served, files in static folder in current folder will automatically be mapped to /static/ and so on.

[1]: https://github.com/amitu/djangothis