Convert your Django views into a collection of static HTML files. Or, put another way, a Django based static-site-generator with few opinions.
This is my attempt at a different type of static site renderer, instead leveraging the availability of Django's staticfiles functionality to leave specifics to someone else :) The theory is thus that you could choose a third party storage from, say, django-storages and plug it into jackfrost
and have things Just Work.
I don't actually know if that's true though.
Release | Status |
---|---|
stable (0.4.0) | |
master |
- There's django-medusa, though it doesn't appear to be active anymore.
- also django-bakery, which takes a different approach whereby one must extend specific views or models.
- Unlike django-medusa there is no autodiscovery, and no requirement that renderers go in a specific place.
- Unlike django-bakery, existing views and models ought to be usable unchanged, because of the renderer approach I've taken, which is more similar to django-medusa or Django RSS Feeds.
pip installing the latest release via PyPI:
pip install django-jackfrost==0.4.0
If you want to get the latest, unstable version, you can use something like this (again with pip) I think:
pip install git+https://github.com/kezabelle/django-jackfrost.git#egg=django-jackfrost
Put jackfrost
into your INSTALLED_APPS
:
INSTALLED_APPS = (
'django.contrib.auth',
# ...
'jackfrost',
# ...
)
which will enable the management command:
python manage.py collectstaticsite --processes=N
Set JACKFROST_STORAGE
to whatever storage backend you'd like to use, in your project's settings. By default, a subclass of django.contrib.staticfiles.storage.StaticFilesStorage
which puts output into a __jackfrost
directory will be used.
If your storage backend needs any arguments that can't be gleaned from individual settings, you can set JACKFROST_STORAGE_KWARGS
to a dictionary of arguments to be used when instantiating the JACKFROST_STORAGE
Add a JACKFROST_RENDERERS
setting, which should be a list or tuple of dotted paths to python classes or functions, much like MIDDLEWARE_CLASSES
, TEMPLATE_CONTEXT_PROCESSORS
etc:
JACKFROST_RENDERERS = (
'myapp.renderers.MyModelRenderer',
'my_other_app.utils.SomeOtherRenderer',
)
In theory, I don't care whether your JACKFROST_RENDERERS
are functions or classes; if it's a class it must implement __call__
. Either way, it should, when called, return a number of URL paths to be consumed.
If you have a model which has a get_absolute_url
method, your renderer can be as simple as:
from jackfrost.models import ModelRenderer
class MyModelRenderer(ModelRenderer):
def get_model(self):
return MyModel
If you need to customise the queryset, there is a get_queryset
method which can be replaced. There is also a get_urls
method, if you need to go totally off-reservation.
Reading from sitemaps
Giving jackfrost
the dotted path to a standard Django sitemap as one of the JACKFROST_RENDERERS
should do the right thing, and get the URLs out of the sitemap itself without you needing to do anything or write a new renderer.
Reading from django-medusa
In theory, giving jackfrost
the dotted path to a subclass of the django-medusa BaseStaticSiteRenderer should do the right thing, and get the URLs out of the medusa renderer itself, without you doing anything. It will avoid going through the medusa rendering process, instead it'll go through mine.
Reading from Django RSS Feeds
Giving jackfrost
the dotted path to a subclass of a Feed should do the right thing, and get the URLs out by asking the Feed for the item_link
for everything in items
, without you doing anything.
The most basic renderer would be:
def myrenderer_yielding():
yield reverse('app:name')
or:
def myrenderer():
return [reverse('app:name')]
Renderers may also be classes:
class MyRenderer(object):
__slots__ = ()
def __init__(self):
pass
def __call__(self):
yield reverse('app:name')
There are 8 signals in total:
build_started
is fired when the management command is run.reader_started
is fired when aURLReader
instance begins working.read_page
is fired when aURLReader
successfully gets a URL's content.reader_finished
is fired when aURLReader
instance completes.writer_started
is fired when aURLWriter
instance begins working.write_page
is fired just after the content is written to the storage backend.writer_finished
is fired when theURLWriter
completesbuild_finished
fires at the end of the management command.
Additionally, there is a listener, jackfrost.receivers.build_page_for_obj
which is suitable for being used as a pre_save
or post_save
receiver for a Model
instance, and will attempt to build just the get_absolute_url
for that object.
If a Model
instance implements a jackfrost_can_build
method, this is checked before building the static page. If jackfrost_can_build
returns False
, the page won't get built. Any other value will result in it being built.
If a Model
instance implements a jackfrost_urls
method, this is used instead of the get_absolute_url
, and should return an iterable of all the URLs to consider building.
If the Model
instance has a get_list_url
method, that page will also be built. Useful for updating any ListView
pages, etc.
Where possible, jackfrost
will attempt to compensate for redirects (301, 302 etc) by writing an HTML page with a <meta refresh>
tag pointing at the final endpoint. The template used is called 301.html.
Additionally, static pages for 401, 403, 404 and 500 errors will be built from their respective templates, if they exist. Useful if you want to wire up Apache ErrorDocument
directives or whatever.
Given a complete clone:
python setup.py test