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

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