A smooth, flexible CMS to create the designs you like,
built on top of the powerful Django framework.

Django 2.0 support is here!

Long time no blog.. However, this one brings some good news!

Most of our packages have been updated to support Django 2.0. They are easily to recognize, because all upgraded packages have been given a “2.0” version number. This choice simplifies the version management across all packages, and marks a clear support baseline.

The 2.0 packages support Django 1.10, 1.11 and 2.0. If you still run on Django 1.8, you can use the 1.x series. There have been a few backports to ease the transition for old projects. Available are:

django-fluent-blogs == 2.0
django-fluent-comments == 2.0
django-fluent-contents == 2.0
django-fluent-dashboard == 1.0
django-fluent-pages == 2.0.2
django-fluent-utils == 2.0
fluentcms-button == 2.0
fluentcms-contactform == 2.0
fluentcms-cookielaw == 2.0
fluentcms-countdown == 1.2
fluentcms-emailtemplates == 2.0
fluentcms-googlemaps == 1.4  # dependencies still need upgrading
fluentcms-jumbotron == 2.0
fluentcms-pager == 2.0
fluentcms-privatenotes == 2.0

The dependencies may not follow this version scheme, but are nonetheless compatible with Django 2.0:

django-any-imagefield == 0.9
django-any-urlfield == 2.4.2
django-parler == 1.9.1
django-polymorphic == 2.0
django-polymorphic-tree == 1.5
django-tag-parser == 3.1
django-template-analyzer == 1.6.1
django-wysiwyg == 0.7.1

One of the visible changes is the dashboard intro page, It uses flaticons now, to modernize the look!

Preliminary Django 1.9 support

Work is underway to make django-fluent compatible with Django 1.9. The following packages have been upgraded to support Django 1.9:

  • django-fluent-blogs
  • django-fluent-contents
  • django-fluent-comments
  • django-fluent-dashboard
  • django-any-urlfield
  • django-parler
  • django-polymorphic (with the exception of the admin)
  • django-polymorphic-tree
  • django-slug-preview

Work for django-fluent-pages is still underway. A 1.0b1 release is issued for testing. However, it does have issues with the admin and page moving that still need to be fixed. If you can help, please join in!

New features

  • A slug preview field, that shows which part of the URL will get the slug.
  • blogs: support for translatable category titles, using django-categories-i18n instead of django-categories.
  • blogs: a migrate_blog_categories command, to upgrade the category model.
  • pages: translations for the textfile pagetype.
  • pages: multiple fallback languages in URLs.
  • pages: draft CSS class in the menu, and “is_child_active” variable for templates.
  • contents: text-filters, to perform post-processing filters on textual content (e.g. apply smartypants, add soft-hyphenation).
  • contents: API for search engine integration.
  • contents: a debug toolbar panel for locating content.

The project template has been updated to use Django 1.8 with the latest package versions.

Django 1.7 and 1.8 support is here!

All packages have been upgraded to support Django 1.7 and 1.8! Since Django 1.8 is a new long-term-support release, we’ve fast-tracked those releases to make the latest features available.

These features include:

  • Multilingual support for all modules
  • Multisite support for all modules
  • Python 3 support!
  • Improved caching for performance
  • Additional SEO fields (e.g. page title)

For existing projects, you may want to upgrade to Django 1.7 only, until all other projects have migrated.
In our case, that is django-categories and django-contrib-comments.

New versions

Use the following versions in your requirements file:

django-fluent-pages >= 0.9
-fluent-contents >= 1.0.1
-fluent-blogs >= 1.0
-fluent-dashboard >= 0.5
-fluent-comments >= 1.0.2


Any requirements will be installed, but you can state these explicitly:

django-admin-tools >= 0.5.2
-any-imagefield >= 0.8.2
-any-urlfield >= 2.1.1
-fluent-utils >= 1.2.1
-polymorphic >= 0.7
-parler >= 1.4
-polymorphic-tree >= 1.1
-tag-parser >= 2.1
-taggit >= 0.13
-taggit-autosuggest >= 0.2.7
-analyzer >= 1.5
-threadedcomments >= 1.0b1
-tinymce >= 1.5.3
-wysiwyg >= 0.7.0

# For debugging:
-debugtools >= 1.3


Note: upgrading from Django 1.6

Once you use Django 1.7, the included South migrations are ignored. Hence, when upgrading both Django and the CMS pacakges you need to upgrade the CMS modules first while keeping the project on Django 1.6. After deploying that on production (so migrations have been applied), you can remove South and upgrade the project to Django 1.7. The native Django migrations will be applied (faked in fact).

Note: Comments module on Django 1.7/1.8

In Django 1.7 and 1.8, comments module relies on the new django-contrib-comments module. This is not compatible with Django 1.8 yet, please help these guys create a new release! In the meantime, use the following requirement to have Django 1.7 support:

# For proper Django 1.7 support:
# Place before django-fluent-comments or django-threadedcomments, so it installs this first
-e git+https://github.com/django/django-contrib-comments.git@8a99ed810e9e94cb9dff1c362b2c4ebe2e37dead#egg=django-contrib-comment


Try it out, and let us know how it works!

Any issues can be posted in the GitHub issue trackers, posted at the django-fluent mailinglist or asked at #django-fluent on Freenode.

Tip: making SSL-only websites

When deploying websites, adding SSL should in my opinion be a standard practise. This for a few reasons:

  • Protecting the privacy of your users.
  • Protecting your visitors when they use Wifi-hotspots
  • Protecting your admin interface against session-cookie-theft.
  • Making life harder for government agencies to read traffic.

There are a few things to do to implement SSL (actually TLS) property

1. Django configuration

When a site is accessable over HTTPS only, the following settings give maximum security:

# For https only sites:

# Improve cookie protection
SESSION_COOKIE_HTTPONLY = True  # can't read cookie from JavaScript, default in modern Django

# Enable clickjacking protection 
# Can be overwritten per view using the @xframe_options_.. decorators
X_FRAME_OPTIONS = 'DENY'        # Prevent iframes, alt: SAMEORIGIN.

    # ...
    # ...

The first two fields avoid exposing the cookie over HTTP, which could give attackers an opportunity to read the cookie. When a hacker is able to read the session-cookie, they can impersonate themselves as your account, and log into your site. This is obviously a security risk.

The remaining settings are optional, but give better security. A clickjacking site for instance, tries show your site in an iframe, and overlay an element to catch user input.

2. Nginx configuration

Just adding SSL settings to Nginx is not enough. To get an A+ score in the SSL test you need to configure the SSL ciphers properly. There are various combinations, this is an example:


    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # Diffie-Hellman parameter for DHE ciphersuites, recommended at least 2048 bits
    ssl_dhparam /etc/ssl/private/dhparam.pem;

    # Enforce strict policies in browsers, and be SSL-only
    add_header Strict-Transport-Security "max-age=31536000";  # optional: ; includeSubdomains
    add_header X-Content-Type-Options nosniff;

 This combination ensures that:

  • Browsers get the best possible encryption by default
  • ECDH ciphers are preferred, which give Perfect Forward Secrecy.
  • SSL v3 and RC4 are disabled, which is really insecure.

Please verify these cipher settings against the current SSL test suite, it’s possible you may need other ciphers in the future. The dhparam file is needed to give a higher key exchange for the DH-ciphers. Generate this file using:

/usr/bin/openssl dhparam -out /etc/ssl/private/dhparam.pem 4096

It takes a few minutes to generate this file!

3. Updating content

When making sites SSL-only, modern browsers will no longer allow “mixed content”. This can effect staff users that write content for the website. For example, when embedding a YouTube video, the URL should use the https:// protocol prefix. Browsers won’t load the video otherwise. You can also use // as prefix, so browsers pick the current protocol automatically.

Bonus: you can add Content Security Policy headers to limit the domains for images, scripts, iframes that can be embedded.

Other resources

Other good resources about security:

New beta releases of all packages, for improved multilingual and Django 1.7 support

New packages of the django-fluent apps have been released.
These packages support the latest multilingual features (such as translatable SEO fields),
and Django 1.7 support is included for most apps.

The following package versions can be used in the requirements.txt for Django 1.7 support:

django-fluent-pages >=0.9b4
-fluent-contents >=1.0c3
-fluent-blogs >=1.0b4

If you've used the previous beta versions, please note the upgrade notices. Some things had to be changed in a backwards-incompatible way for Django 1.7 support and multilingual support in SEO fields. See: https://github.com/edoburu/django-fluent-pages/blob/master/CHANGES.rst#upgrade-notices for all details.

Any dependencies will be installed automatically:

django-admin-tools >=0.5.2
-any-imagefield >=0.8.2
-any-urlfield >=2.0.3
-polymorphic >=0.6
-parler >=1.2.1
django-polymorphic-tree >=1.0.1
-tag-parser >=2.0
-taggit >=0.12.2
-taggit-autosuggest ==0.2.5
-tinymce >=1.5.3
-wysiwyg >=0.7.0

Note, the following packages are not checked yet for Django 1.7 support:

django-fluent-dashboard >=0.3.6
-fluent-comments >=1.0b1

The project template has also been improved and updated:

django-parler 1.0 is out!

To make creating multilingual websites easier, django-parler 1.0 has just been released! This package allows creating translatable user data, by translating Django model fields.

The release includes full documentation, and a few other awesome features:

  • Python 3 support
  • Caching translations for performance
  • Prefetch support for performance
  • Support translatable slugs
  • Switch the language of the current page easily.
  • Easy migration for projects that used django-hvad before.
  • ORM methods for filtering translated models.

This is also the base for the next release of django-fluent-pages and django-fluent-contents, which also have multilingual support in git.

Displaying a staff-toolbar

To make it easier for staff users to edit the current object in the admin, we've just released a new package: django-staff-toolbar. This allows displaying a nice menu at the website frontend:

The admin object is automatically detected, but can be overwritten in case the view doesn't provide an "object" variable in the template. See the README for more information

Lightning talk at DjangoCon EU 2014

For multilingual support, django-parler is at the base of the CMS. It provides the multilingual support which django-fluent-pages builds upon.

This presentation also explain why django-modeltranslation or django-hvad were nog used, and what complex inheritance were faced. Now features such as:

  • Python 3 support
  • Prefetching translations
  • Caching
  • High-level features such as `{% get_translated_url %}`.
  • Admin inlines

Licensing your Django code

When you release your software as Open Source for Django projects, the licenses choices boil down to a few choices (namely: BSD/MIT, LGPL, MPL or Apache 2). Which license to use? Here is a powerful reasoning why:

The road to multilingual support

In the current git-versions of django-fluent, multilingual support has been added. The translation support is based on django-parler.

Not django-hvad?

Our original plan was to use django-hvad as backend module. However, this turned out to be very difficult. The sad truth is that while django-hvad has a nice admin interface, table layout and model API, it also overrides much of the default behavior of querysets, the admin and model metaclasses. Currently, this prevents combining django-hvad with django-polymorphic or django-mptt, which are both used in django-fluent-pages.

A fresh start...

When investigating other multilingual packages, they either appeared to be outdated, store translations in the same table (too inflexible for us) or only provided a model API. Hence, there was a need for a new solution, using a simple, crude but effective API.

To get things started, multilingual support was coded directly within django-fluent-pages, while keeping a future django-hvad transition in mind. Instead of doing metaclass operations, the "shared model" just proxied all attributes to the translated model (all manually constructed). Queries just had to be performed using.filter(translations__title=..). This proved to be a sane solution and quickly it turned out that this code deserved a separate package. Some other modules (i.e. blogging, and shared contents) needed this functionality too.

..leading to django-parler

End of the story: we've created a new package; django-parler. As the tagline states, it easily translates "cheese omelet" into "omelette du fromage". :-) This package is an attempt to combine the best of both worlds; the API simplicity of django-hvad with the crude, but effective solution of proxying translated attributes. And yes, we've added some metaclass magic too - to make life easier - without loosing the freedom of manually using the API at your will.

Fork me on GitHub