<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: static-generator</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/static-generator.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2021-07-28T20:23:44+00:00</updated><author><name>Simon Willison</name></author><entry><title>The Baked Data architectural pattern</title><link href="https://simonwillison.net/2021/Jul/28/baked-data/#atom-tag" rel="alternate"/><published>2021-07-28T20:23:44+00:00</published><updated>2021-07-28T20:23:44+00:00</updated><id>https://simonwillison.net/2021/Jul/28/baked-data/#atom-tag</id><summary type="html">
    &lt;p&gt;I've been exploring an architectural pattern for publishing websites over the past few years that I call the "Baked Data" pattern. It provides many of the advantages of static site generators while avoiding most of their limitations. I think it deserves to be used more widely.&lt;/p&gt;
&lt;p&gt;I define the Baked Data architectural pattern as the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Baked Data: bundling a read-only copy of your data alongside the code for your application, as part of the same deployment&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Most dynamic websites keep their code and data separate: the code runs on an application server, the data lives independently in some kind of external data store - something like PostgreSQL, MySQL or MongoDB.&lt;/p&gt;
&lt;p&gt;With Baked Data, the data is deployed as part of the application bundle. Any time the content changes, a fresh copy of the site is deployed that includes those updates.&lt;/p&gt;
&lt;p&gt;I mostly use SQLite database files for this, but plenty of other formats can work here too.&lt;/p&gt;
&lt;p&gt;This works particularly well with so-called "serverless" deployment platforms - platforms that support stateless deployments and only charge for resources spent servicing incoming requests ("scale to zero").&lt;/p&gt;
&lt;p&gt;Since every change to the data results in a fresh deployment this pattern doesn't work for sites that change often - but in my experience many content-oriented sites update their content at most a few times a day. Consider blogs, documentation sites, project websites - anything where content is edited by a small group of authors.&lt;/p&gt;
&lt;h4 id="benefits-of-baked-data"&gt;Benefits of Baked Data&lt;/h4&gt;
&lt;p&gt;Why would you want to apply this pattern? A few reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inexpensive to host&lt;/strong&gt;. Anywhere that can run application code can host a Baked Data application - there's no need to pay extra for a managed database system. Scale to zero serverless hosts such as &lt;a href="https://cloud.google.com/run"&gt;Cloud Run&lt;/a&gt;, &lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt; or &lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt; will charge only cents per month for low-traffic deployments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to scale&lt;/strong&gt;. Need to handle more traffic? Run more copies of your application and its bundled data. Horizontally scaling Baked Data applications is trivial. They're also a great fit to run behind a caching proxy CDN such as Cloudflare or Fastly - when you deploy a new version you can purge that entire cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficult to break&lt;/strong&gt;. Hosting server-side applications on a VPS is always disquieting because there's so much that might go wrong - the server could be compromised, or a rogue log file could cause it to run out of disk space. With Baked Data the worst that can happen is that you need to re-deploy the application - there's no risk at all of data loss, and providers that can auto-restart code can recover from errors automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-side functionality is supported&lt;/strong&gt;. Static site generators provide many of the above benefits, but with the limitation that any dynamic functionality needs to happen in client-side JavaScript. With a Baked Data application you can execute server-side code too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Templated pages&lt;/strong&gt;. Another improvement over static site generators: if you have 10,000 pages, a static site generator will need to generate 10,000 HTML files. With Baked Data those 10,000 pages can exist as rows in a single SQLite database file, and the pages can be generated at run-time using a server-side template.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to support multiple formats&lt;/strong&gt;. Since your content is in a dynamic data store, outputting that same content in alternative formats is easy. I use Datasette plugins for this: &lt;a href="https://datasette.io/plugins/datasette-atom"&gt;datasette-atom&lt;/a&gt; can produce an Atom feed from a SQL query, and &lt;a href="https://datasette.io/plugins/datasette-ics"&gt;datasette-ics&lt;/a&gt; does the same thing for iCalendar feeds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrates well with version control&lt;/strong&gt;. I like to keep my site content under version control. The Baked Data pattern works well with build scripts that read content from a git repository and use it to build assets that are bundled with the deployment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="how-to-bake-your-data"&gt;How to bake your data&lt;/h4&gt;
&lt;p&gt;My initial implementations of Baked Data have all used SQLite. It's an ideal format for this kind of application: a single binary file which can store anything that can be represented as relational tables, &lt;a href="https://www.sqlite.org/json1.html"&gt;JSON documents&lt;/a&gt; or &lt;a href="https://simonwillison.net/2020/Jul/30/fun-binary-data-and-sqlite/"&gt;binary objects&lt;/a&gt; - essentially anything at all.&lt;/p&gt;
&lt;p&gt;Any format that can be read from disk by your dynamic server-side code will work too: YAML or CSV files, Berkeley DB files, or anything else that can be represented by a bucket of read-only bytes in a file on disk.&lt;/p&gt;
&lt;p&gt;[I have a hunch that you could even use something like PostgreSQL, MySQL or Elasticsearch by packaging up their on-disk representations and shipping them as part of a Docker container, but I've not tried that myself yet.]&lt;/p&gt;
&lt;p&gt;Once your data is available in a file, your application code can read from that file and use it to generate and return web pages.&lt;/p&gt;
&lt;p&gt;You can write code that does this in any server-side language. I use Python, usually with my &lt;a href="https://datasette.io/"&gt;Datasette&lt;/a&gt; application server which can read from a SQLite database file and use &lt;a href="https://docs.datasette.io/en/stable/custom_templates.html"&gt;Jinja templates&lt;/a&gt; to generate pages.&lt;/p&gt;
&lt;p&gt;The final piece of the puzzle is a build and deploy script. I use GitHub Actions for this, but any CI tool will work well here. The script builds the site content into a deployable asset, then deploys that asset along with the application code to a hosting platform.&lt;/p&gt;
&lt;h4 id="baked-data-datasette-io"&gt;Baked Data in action: datasette.io&lt;/h4&gt;
&lt;p&gt;The most sophisticated Baked Data site I've published myself is the official website for my Datasette project, &lt;a href="https://datasette.io/"&gt;datasette.io&lt;/a&gt; - source code &lt;a href="https://github.com/simonw/datasette.io"&gt;in this repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2021/datasette-io-baked-data.png" alt="A screenshot of the datasette.io homepage" style="max-width:100%;" /&gt;&lt;/p&gt;
&lt;p&gt;The site is deployed using Cloud Run. It's actually a heavily customized Datasette instance, using &lt;a href="https://github.com/simonw/datasette.io/blob/main/templates/index.html"&gt;a custom template&lt;/a&gt; for the homepage, &lt;a href="https://github.com/simonw/datasette.io/tree/main/templates/pages"&gt;custom pages&lt;/a&gt; for other parts of the site and the &lt;a href="https://datasette.io/plugins/datasette-template-sql"&gt;datasette-template-sql&lt;/a&gt; plugin to execute SQL queries and display their results from those templates.&lt;/p&gt;
&lt;p&gt;The site currently runs off &lt;a href="https://datasette.io/-/databases"&gt;four database files&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://datasette.io/content"&gt;content.db&lt;/a&gt; has most of the site content. It is built inside GitHub Actions by the &lt;a href="https://github.com/simonw/datasette.io/blob/main/scripts/build.sh"&gt;build.sh&lt;/a&gt; script, which does the following:
&lt;ul&gt;
&lt;li&gt;Import the contents of the &lt;a href="https://github.com/simonw/datasette.io/blob/main/news.yaml"&gt;news.yaml&lt;/a&gt; file into a &lt;a href="https://datasette.io/content/news"&gt;news&lt;/a&gt; table using &lt;a href="https://datasette.io/tools/yaml-to-sqlite"&gt;yaml-to-sqlite&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Import the markdown files from the &lt;a href="https://github.com/simonw/datasette.io/tree/main/for"&gt;for/ folder&lt;/a&gt; (use-cases for Datasette) into the &lt;a href="https://datasette.io/content/uses"&gt;uses&lt;/a&gt; table using &lt;a href="https://datasette.io/tools/markdown-to-sqlite"&gt;markdown-to-sqlite&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Populate the &lt;a href="https://datasette.io/content/plugin_repos"&gt;plugin_repos&lt;/a&gt; and &lt;a href="https://datasette.io/content/plugin_repos"&gt;tool_repos&lt;/a&gt; single-column tables using data from more YAML files. These are used in the next step.&lt;/li&gt;
&lt;li&gt;Runs the &lt;a href="https://github.com/simonw/datasette.io/blob/main/build_directory.py"&gt;build_directory.py&lt;/a&gt; Python script. This uses the GitHub GraphQL API to fetch information about all of those plugin and tool repositories, including their README files and their most recent tagged &lt;a href="https://datasette.io/content/releases"&gt;releases&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Populates a &lt;a href="https://datasette.io/content/stats"&gt;stats&lt;/a&gt; table with the latest download statistics for all of the Datasette ecosystem PyPI packages. That data is imported from a &lt;code&gt;stats.json&lt;/code&gt; file in my &lt;a href="https://github.com/simonw/package-stats"&gt;simonw/package-stats&lt;/a&gt; repository, which is itself populated by this &lt;a href="https://github.com/simonw/package-stats/blob/main/.github/workflows/fetch_stats.yml"&gt;git scraping script&lt;/a&gt; that runs in GitHub Actions. I also use this for my &lt;a href="https://observablehq.com/@simonw/datasette-downloads-per-day-with-observable-plot"&gt;Datasette Downloads Observable notebook&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://datasette.io/blog"&gt;blog.db&lt;/a&gt; contains content from my blog that carries any of the &lt;a href="https://simonwillison.net/tags/datasette/"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/dogsheep/"&gt;dogsheep&lt;/a&gt; or &lt;a href="https://simonwillison.net/tags/sqliteutils/"&gt;sqliteutils&lt;/a&gt; tags.
&lt;ul&gt;
&lt;li&gt;This is fetched by the &lt;a href="https://github.com/simonw/datasette.io/blob/main/fetch_blog_content.py"&gt;fetch_blog_content.py&lt;/a&gt; script, which hits the paginated per-tag Atom feed for my blog content, &lt;a href="https://github.com/simonw/simonwillisonblog/blob/a5b53a24b00d4c95c88c8371cfc17453b0726c23/blog/views.py#L411-L421"&gt;implemented in Django here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://datasette.io/docs-index"&gt;docs-index.db&lt;/a&gt; is a database table containing the documentation for the most recent stable Datasette release, broken up by &lt;a href="https://datasette.io/docs-index/sections"&gt;sections&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;This database file is downloaded from a separate site, &lt;a href="https://stable-docs.datasette.io/"&gt;stable-docs.datasette.io&lt;/a&gt;, which is built and deployed as &lt;a href="https://github.com/simonw/datasette/blob/0.58.1/.github/workflows/publish.yml#L60-L98"&gt;part of Datasette's release process&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://datasette.io/dogsheep-index"&gt;dogsheep-index.db&lt;/a&gt; is the search index that powers site search (e.g. &lt;a href="https://datasette.io/-/beta?q=dogsheep"&gt;this search for dogsheep&lt;/a&gt;).
&lt;ul&gt;
&lt;li&gt;The search index is built by &lt;a href="https://datasette.io/plugins/dogsheep-beta"&gt;dogsheep-beta&lt;/a&gt; using data pulled from tables in the other database files, as configured by &lt;a href="https://github.com/simonw/datasette.io/blob/main/templates/dogsheep-beta.yml"&gt;this YAML file&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The site is automatically deployed once a day by &lt;a href="https://github.com/simonw/datasette.io/blob/main/.github/workflows/deploy.yml"&gt;a scheduled action&lt;/a&gt;, and I can also manually trigger that action if I want to ensure a new software release is reflected on the homepage.&lt;/p&gt;
&lt;h4 id="other-real-world-examples"&gt;Other real-world examples of Baked Data&lt;/h4&gt;
&lt;p&gt;I'm currently running two other sites using this pattern:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.niche-museums.com/"&gt;Niche Museums&lt;/a&gt; is my blog about tiny museums that I've visited. Again, it's Datasette with custom templates. Most of the content comes from this &lt;a href="https://github.com/simonw/museums/blob/main/museums.yaml"&gt;museums.yaml&lt;/a&gt; file, but I also run &lt;a href="https://github.com/simonw/museums/blob/main/annotate_timestamps.py"&gt;a script&lt;/a&gt; to figure out when each item was created or updated from the git history.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://til.simonwillison.net/"&gt;My TILs site&lt;/a&gt; runs on &lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt; and is built from my &lt;a href="https://github.com/simonw/til"&gt;simonw/til&lt;/a&gt; GitHub repository by &lt;a href="https://github.com/simonw/til/blob/main/build_database.py"&gt;this build script&lt;/a&gt; (populating &lt;a href="https://til.simonwillison.net/tils"&gt;this tils table&lt;/a&gt;). It uses the GitHub API to convert GitHub Flavored Markdown to HTML. I'm also running &lt;a href="https://github.com/simonw/til/blob/main/generate_screenshots.py"&gt;a script&lt;/a&gt; that generates small screenshots of each page and stashes them in a BLOB column in SQLite in order to provide social media preview cards, see &lt;a href="https://simonwillison.net/2020/Sep/3/weeknotes-airtable-screenshots-dogsheep/#weeknotes-2020-09-03-social-media-cards-tils"&gt;Social media cards for my TILs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My favourite example of this pattern in a site that I haven't worked on myself is &lt;a href="https://www.mozilla.org/"&gt;Mozilla.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;They started using SQLite back in 2018 in a system they call Bedrock - Paul McLanahan provides &lt;a href="https://mozilla.github.io/meao/2018/03/28/bedrock-the-sqlitening/"&gt;a detailed description&lt;/a&gt; of how this works.&lt;/p&gt;
&lt;p&gt;Their site content lives in a ~22MB SQLite database file, which is built and uploaded to S3 and then downloaded on a regular basis to each of their application servers.&lt;/p&gt;
&lt;p&gt;You can view &lt;a href="https://www.mozilla.org/healthz-cron/"&gt;their healthcheck page&lt;/a&gt; to see when the database was last downloaded, and grab a copy of the SQLite file yourself. It's fun to explore that using Datasette:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2021/mozilla-site-content.png" alt="Datasette running against the Mozilla contentncards_contentcard table" style="max-width:100%;" /&gt;&lt;/p&gt;
&lt;h4 id="compared-to-ssgs"&gt;Compared to static site generators&lt;/h4&gt;
&lt;p&gt;Static site generators have exploded in popularity over the past ten years. They drive the cost of hosting a site down to almost nothing, provide excellent performance, work well with CDNs and produce sites that are extremely unlikely to break.&lt;/p&gt;
&lt;p&gt;Used carefully, the Baked Data keeps most of these characteristics while still enabling server-side code execution.&lt;/p&gt;
&lt;p&gt;My example sites use this in a few different ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;datasette.io &lt;a href="https://datasette.io/-/beta?q=search"&gt;provides search&lt;/a&gt; across 1,588 different pieces of content, plus &lt;a href="https://datasette.io/plugins?q=ics"&gt;simpler search&lt;/a&gt; on the plugins and tools pages.&lt;/li&gt;
&lt;li&gt;My TIL site also &lt;a href="https://til.simonwillison.net/tils/search?q=search"&gt;provides search&lt;/a&gt;, as &lt;a href="https://www.niche-museums.com/browse/search?q=bigfoot"&gt;does Niche Museums&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;All three sites provide Atom feeds that are configured using a server-side SQL query: &lt;a href="https://datasette.io/content/feed.atom"&gt;Datasette&lt;/a&gt;, &lt;a href="https://www.niche-museums.com/browse/feed.atom"&gt;Niche Museums&lt;/a&gt;, &lt;a href="https://til.simonwillison.net/tils/feed.atom"&gt;TILs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Niche Museums offers a "Use my location" button which then serves &lt;a href="https://www.niche-museums.com/?latitude=37.5&amp;amp;longitude=-122.5"&gt;museums near you&lt;/a&gt;, using &lt;a href="https://www.niche-museums.com/browse/nearby"&gt;a SQL query&lt;/a&gt; that makes use of the &lt;a href="https://datasette.io/plugins/datasette-haversine"&gt;datasette-haversine&lt;/a&gt; plugin.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A common complaint about static site generators when used for larger sites is that build times can get pretty long if the builder has to generate tens of thousands of pages.&lt;/p&gt;
&lt;p&gt;With Baked Data, 10,000 pages can be generated by a single template file and 10,000 rows in a SQLite database table.&lt;/p&gt;
&lt;p&gt;This also makes for a faster iteration cycle during development: you can edit a template and hit "refresh" to see any page rendered by the new template instantly, without needing to rebuild any pages.&lt;/p&gt;
&lt;h4 id="give-this-a-go"&gt;Want to give this a go?&lt;/h4&gt;
&lt;p&gt;If you want to give the Baked Data pattern a try, I recommend starting out using the combination of &lt;a href="https://datasette.io/"&gt;Datasette&lt;/a&gt;, &lt;a href="https://docs.github.com/en/actions"&gt;GitHub Actions&lt;/a&gt; and &lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt;. Hopefully the examples I've provided above are a good starting point - also feel free to reach out to me &lt;a href="https://twitter.com/"&gt;on Twitter&lt;/a&gt; or in &lt;a href="https://github.com/simonw/datasette/discussions"&gt;the Datasette Discussions forum&lt;/a&gt; with any questions.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/definitions"&gt;definitions&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/design-patterns"&gt;design-patterns&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/static-generator"&gt;static-generator&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/baked-data"&gt;baked-data&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="definitions"/><category term="design-patterns"/><category term="sqlite"/><category term="static-generator"/><category term="datasette"/><category term="baked-data"/></entry><entry><title>Django Bakery</title><link href="https://simonwillison.net/2018/Jun/16/django-bakery/#atom-tag" rel="alternate"/><published>2018-06-16T01:49:35+00:00</published><updated>2018-06-16T01:49:35+00:00</updated><id>https://simonwillison.net/2018/Jun/16/django-bakery/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://django-bakery.readthedocs.io/en/latest/"&gt;Django Bakery&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
“A set of helpers for baking your Django site out as flat files”. Released by the LA Times Data Desk, who use it for a large number of projects from election results to data journalism interactives. Statically publishing these projects to S3 lets them handle huge traffic spikes at a very low cost.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/palewire/status/1007721981179883520"&gt;@palewire&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/data-journalism"&gt;data-journalism&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/s3"&gt;s3&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/static-generator"&gt;static-generator&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ben-welsh"&gt;ben-welsh&lt;/a&gt;&lt;/p&gt;



</summary><category term="data-journalism"/><category term="django"/><category term="s3"/><category term="static-generator"/><category term="ben-welsh"/></entry><entry><title>Announcing StaticGenerator for Django</title><link href="https://simonwillison.net/2008/Jan/7/announcing/#atom-tag" rel="alternate"/><published>2008-01-07T21:26:41+00:00</published><updated>2008-01-07T21:26:41+00:00</updated><id>https://simonwillison.net/2008/Jan/7/announcing/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://superjared.com/entry/announcing-staticgenerator-django/"&gt;Announcing StaticGenerator for Django&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Simple but powerful static file generator for Django applications—just tell it about your model instances and it will create an entire static site based on calling get_absolute_url() on each one. Uses signals to repopulate the cache when a model changes.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/caching"&gt;caching&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jared-kuolt"&gt;jared-kuolt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/orm"&gt;orm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/performance"&gt;performance&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/static"&gt;static&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/static-generator"&gt;static-generator&lt;/a&gt;&lt;/p&gt;



</summary><category term="caching"/><category term="django"/><category term="jared-kuolt"/><category term="orm"/><category term="performance"/><category term="static"/><category term="static-generator"/></entry></feed>