Table of Content

Documentation of Dynastie version 0.3

This document is a guide to install and configure Dynastie.


First you need to install Django >= 1.4 . libapache2-mod-wsgi if you want to use Dynastie with Apache. Optionally you can install PyGments.

You can find a whole example of all capabilities of dynastie in the sample site sites/blog.soutade.fr.


Checkout the project. If you use Apache, this is a sample configuration file :

<VirtualHost *:80> ServerName dynastie.soutade.fr

DocumentRoot /var/www/dynastie

WSGIScriptAlias / /var/www/dynastie/wsgi.py

CustomLog /var/log/apache2/soutade.fr_dynastie_access.log vhost_combined

Alias /static /var/www/dynastie/static

    <Directory /var/www/dynastie/sites>
           Order allow,deny
           Allow from all


I also use nginx to serve static HTML (and acts as a front server for Apache). Here is my configuration :

server { listen 80; ## listen for ipv4 listen [::]:8000 default ipv6only=on; ## listen for ipv6

server_name  blog.soutade.fr;

log_format apache '$server_name:$server_port $remote_addr - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent"';

access_log  /var/log/apache2/soutade.fr_access.log apache;

location / {
    root   /var/www/dynastie/sites/blog.soutade.fr; 
    index  index.html index.htm;
    gzip_static on;

location /comment {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;

    proxy_set_header Host dynastie.soutade.fr;

    proxy_read_timeout 120;

location /search {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;

    proxy_set_header Host dynastie.soutade.fr;

    proxy_read_timeout 120;

location = /favicon.ico { access_log off; log_not_found off; }
location ~ /\. { deny all; access_log off; log_not_found off; }




First copy dynastie.bdd.init in dynastie.bdd. Do a ./manage.py syncdb. Then update the root path in wsgy.py (with $PWD/..).


After that, you need to create one or more users. Go to the Users section. By default there is an user : admin/admin.


Then you can create a blog. Be careful : $(blog.name) must be an URI like "blog.soutade.fr", it will be used like this in some parts of Dynastie. Now go to your new created blog.


Once your blog is created, you can add categories.


They are automatically created during post creation/edition. But you can edit or remove them.


Finally you can add posts and generate your blog. You may notice that Dynastie compress all generated files. nginx can use these pre compressed files to speed up the transfert ! Search is updated when post are updated. To edit your posts you have two options : WYSIWYG HTML editor (TinyMCE) and Text editor that understands Markdown syntax (with some enhancements). You can also save them as drafts to publish later (creation date will be updated when turned from draft to post).


Dynastie has a simple policy : * blogs sources directory are under sites/$(blog.name) * blogs output directory is sites/$(blog.name)output * All file/directory that do not starts with "" is copied from source to output * Some special directories like "_post" or "_draft" are automatically created and contains original posts sources


The directory "images" inside sites/$(blog.name) can be scanned by tinyMCE at edit time to retrieve the images of the current month. To do that, it must have a special format :


year and months must be numeric values : 2010, 2011, 2012... for years and 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12 for months


Dynastie acts like an XSLT processor. It combines metadata, posts and templates to create a valid HTML output. Templates are simply HTML files containing special directives starting with "dyn:". The associated namespace is xmlns:dyn="http://indefero.soutade.fr/p/dynastie". Each time a directive is found, it will be replaced (if it's a valid directive) to its content. Example : <dyn:title> will be replaced by <div class="title">POST TITLE</div>.


Dynastie has a system based on "generators". A generator is a piece of software that creates an output. For example the "category" generator generate indexes for each categories of the blog. Most of them uses a template as input to integrate posts content, generally it's "_$(generator.name).html". They also decode dyn: directives. Current available generators are :

  • index
  • post
  • category
  • tag
  • archive
  • atom
  • rss

You can create a file named _generators that will list all generators you want to use (one per line). If it doesn't exists, all generators will be called. For caching optimization, it's recommended to set "post" generator at first. You can disable a generator in _generator by preprending with # (comment).

All generators inherits from "index" generator (it has the same properties).


Generate root index files.

  • Input : _index.html
  • Output : /indexXXX.html
  • Supports : <dyn:base>, <dyn:replace> with dyn:blog_id, dyn:post_url, dyn:post_full_url, <dyn:posts limit="X">, <dyn:title [link="1"]> (current post title. If link is set an hyperlink is created to post URL), <dyn:recents limit="X"> (next X posts, if X is not defined, X=5), <dyn:navigation> (navigation bar), <dyn:tags>, <dyn:first_page_only>, <dyn:ljdc_last>, <dyn:comments_count>, <dyn:category_name>,


Generate posts output.

  • Input : _post.html
  • Output : /post/year/month/$(post.name).html
  • Supports : <dyn:meta name="keywords|title|description|author"> (add meta tag), <dyn:post> (post template), <dyn:replace> with dyn:post_id, dyn:comment_index, dyn:comment_id, dyn:blog_id, <dyn:comments>
  • Excluded : <dyn:posts>, <dyn:navigation>, <dyn:recents>


Generate category indexes.

  • Input : _category.html
  • Output : /category/$(category.name)/indexXXX.html
  • Supports : <dyn:category [name="1"] [description="1"]> (category name and/or description)


Generate tag indexes.

  • Input : _tag.html
  • Output : /tag/$(tag.name)/indexXXX.html
  • Supports : <dyn:tag [name="1"] [description="1"]> (tag name and/or description)


Generate archive indexes. For every years != current year.

  • Input : _archive.html
  • Output : /archive/year/indexXXX.html
  • Supports : <dyn:archive [year="1"]> (current archive year)


Generate RSS feeds

  • Input : none
  • Output : /rss.xml
  • Supports : none


Generate ATOM feeds

  • Input : none
  • Output : /atom.xml
  • Supports : none


Generate LJDC (Les joies du codes) indexes

  • Input : _ljdc.xml (must in a special format, see misc/ljdc.perl for further information)
  • Output : /ljdc/indexXXX.html
  • Supports : none

Special directive

base template

One template can include one or more template(s) (not recursive). It's usefull when you want only to modify content part and keep structure.

In the father, describes your base template and add <dyn:block name="YYY"/> where you want your child to be included.

In the child, use <dyn:base file="XXX" block="YYY" xmlns:dyn="http://indefero.soutade.fr/p/dynastie"> to specify the content to be included.


The <dyn:replace> directive allows you to use variables in strings.

For example <dyn:replace div_name="img" some_attribute="dyn:blog_id"> will be replaced by <img some_attribute="4">.


Childs of this directive describes the template of posts. It has an attribute called "limit" which represents the number of posts to display, 5 if not defined. Then you can use : <dyn:date [format="XXX"]> (post date), <dyn:author> (post author), <dyn:tags [link="1"]> (post tags with link or not), <dyn:post_content> (post content) inside <dyn:posts>

Date format are Python strftime formats. By defaults it's '%A, %d %B %Y %H:%m'


As posts, the comments directive includes comments in the post. You can use : <dyn:comment_index> (current comment index), <dyn:comment_author> (current comment author), <dyn:comment_date> (current comment date).


Search is a dynamic service called from static HTML, so you need two servers (or two domains) : one to serve static HTML and another for dynamic parts. Currently the search is basic : each word is indexed into a big database (hash file) and refers to a post number. When the user type "Blue Vehicule", it'll search in the database "blue" and "vehicule" and returns all posts containing these words. Results are ordered by date and number of occurences found (best ranking). If the word is found in a title, it has a best ranking than in the text. It uses "_search.html" template to generate the output. To use search, insert a form like :

<dyn:replace div_name="form" method="POST" action="/search/dyn:blog_id">

<input type="text" name="text"/>
<input type="sumbit" value="Search"/>


Every time you add/edit/delete post, the search database is updated. But if you want to regenerate the search index from scratch, just go to "Generate search index"


Comments are generated within post generation, but you can add them dynamically. Like search, you need another server (or domain) to do that. It uses an anti-robot trick : If the field "email" is not empty, the comment will be rejected. The true "email" field must be called "mel". Field "the_comment" and "author" MUST NOT be empty. You need to specify blog id and parent id to add comment. Here is a sample comment form :

<dyn:replace div_name="form" method="POST" action="/comment/add/dyn:post_id/dyn:comment_id"">

  Auteur :<br/><input type="text" name="author"/><br/><br/>

  e-mail* :<br/><input type="text" name="email"/><input type="text" name="mel"/><br/><br/>

  Le commentaire :<br/><textarea name="the_comment" cols="80" rows="10"> </textarea><br/><br/>

  <input type="submit" value="Commenter"/>


You can set in your CSS : #email {display:none;}

After a comment is added, Dynastie re generate only the post page and redirect user to the new post page. If you display comments count in indexes, you'll have to manually generate your blog to keep them updated.


The coloration in tinyMCE editor is available through the special button "C". It allows to include code that will be colored at generation time. You just have to select the code type and the code style. You need to install PyGments if you want to enable this feature.

Created: 7 years 3 months ago
by Grégory Soutadé

Updated: 7 years 3 months ago
by Grégory Soutadé

Old Revisions