Or use bzr:
bzr branch http://superjared.com/projects/static-generator/code/
Note that version 1.2 has backwards incompatible syntax changes. Instead of passing a list or tuple, you simply pass arguments.
StaticGenerator is a Python class for Django that makes it easy to create static files for lightning fast performance. It accepts strings (URL), Models (class or instance), Managers, and QuerySets in a simple syntax:
# Passing url, a QuerySet and Model
from generator import quick_publish
quick_publish('/', Post.objects.live(), FlatPage)
Deleting files and paths is just as easy:
from generator import quick_delete
quick_delete('/path-to-delete/')
Note: Directory deletion fails silently while failing to delete a file will raise an exception.
Django is fast, especially when properly cached, but not nearly as fast as serving static files. Even when cached, Django requires some processing and memory overhead.
Serving static files directly can be more than 10x faster than through Django, while reducing cpu and memory requirements.
StaticGenerator is a portable class that anyone can use in any application.
For each resource given, the generator creates a static file based on it’s url (the generator traverses each object for its get_absolute_url method) and settings.WEB_ROOT.
For example, if url is /entry/my-blog-entry/ and my settings.WEB_ROOT is /var/www/, the generator creates the file /var/www/entry/my-blog-entry/index.html. Your URLs don’t have to change.
Place generator.py in your Python path, and add WEB_ROOT to settings.py:
# settings.py
WEB_ROOT = '/var/www'
save(), use SignalsIntegrating with existing models is easy using Django’s signal dispatcher. Simply create a function to publish your models, and connect to to the dispatcher:
from django.contrib.flatpages.models import FlatPage
from blog.models import Post
from django.dispatch import dispatcher
from django.db.models import signals
from generator import quick_publish
def publish(sender, instance):
quick_publish(instance, '/')
dispatcher.connect(publish, sender=Post, signal=signals.post_save)
dispatcher.connect(publish, sender=FlatPage, signal=signals.post_save)
Note that if you're not passing a string URL, StaticGenerator expects a get_absolute_url method.
So every time you save a Post or FlatPage it re-creates the static file (notice that I add ‘/’ so my homepage is updated as well). What happens when a comment is added? Just re-publish the corresponding page:
from django.contrib.comments.models import Comment, FreeComment
def publish_comment(sender, instance):
quick_publish(instance.get_content_object())
dispatcher.connect(publish_comment, sender=Comment, signal=signals.post_save)
dispatcher.connect(publish_comment, sender=FreeComment, signal=signals.post_save)
This configuration snippet shows how Nginx can automatically show the index.html page generated by StaticGenerator, and pass all Django requests to Apache.
# This example configuration only shows parts relevant to a Django app
http {
upstream django {
# Apache/mod_python running on port 7000
server example.com:7000;
}
server {
server_name example.com;
root /var/www/;
location / {
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
if (!-f $request_filename) {
proxy_pass http://django;
break;
}
}
}
}
The beauty of the generator is that you choose when and what urls are made into static files. Obviously a contact form or search form won’t work this way, so we just leave them as regular Django requests. In your front-end http server (you are using a front-end web server, right?) just set the URLs you want to be served as static and they’re already being served.
Love it? Hate it? Let me know what you think!