Skip to main content

Django Layers

Travis

Travis


Django Layers makes it possible to serve a set of templates and static resources as defined in settings.py. This means you can serve different HTML, Javascript and CSS to eg. basic mobile devices, smart phones and desktop browsers. These template sets (aka layers) also stack, so if you create foo.html for basic devices it is automatically available for desktop browsers as well. You can override foo.html for desktop browsers.

Installation

  1. Install or add django-layers-hr to your Python path.

  2. Add layers after django.contrib.static to your INSTALLED_APPS setting.

  3. Ensure the app that you will be creating layers for appears first in INSTALLED_APPS else template override won’t work.

Example

Note: there is a working example in the example subdirectory.

We have sites example.com, basic.example.com and smart.example.com. Each of the sites have their own settings.py, thus different Django processes.

Directory structure

templates
    - basic
        - foo.html (1)
        - bar.html (2)
    - smart
        - bar.html (3)
    - web
        - bar.html (4)

static
    - basic
        - foo.css (5)
        - bar.css (6)
    - smart
        - bar.css (7)
    - web
        - bar.css (8)

Settings

We define an “inheritance” hierarchy using a list-of-lists notation.

Two lines of inheritance: basic-smart and basic-web:

LAYERS = {'tree': ['basic', ['smart'], ['web']]}

One lines of inheritance: basic-smart-web.:

LAYERS = {'tree': ['basic', ['smart', ['web']]]}

There are two ways to configure layer lookup for system: specify the current layer in a settings file or look it up from the request. Omit the current key to enable request based lookups:

LAYERS = {'tree': ['basic', ['smart'], ['web']], 'current': 'web'}

Legacy settings require layers to be defined in separate settings files. The example below means we have three settings files, and thus three Django processes. Please migrate to the default tree format.

  • Desktop settings has LAYERS = {'layers': ['basic', 'web']}.

  • Basic settings has LAYERS = {'layers': ['basic']}.

  • Smart settings has LAYERS = {'layers': ['basic', 'smart']}.

Add the loaders and finders to settings. The order is important.

INSTALLED_APPS = (
    'myapp',
    'layers',
    ...
)

TEMPLATE_LOADERS = (
    'layers.loaders.filesystem.Loader',
    'django.template.loaders.filesystem.Loader',
    'layers.loaders.app_directories.Loader',
    'django.template.loaders.app_directories.Loader',
)

STATICFILES_FINDERS = (
    'layers.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'layers.finders.AppDirectoriesFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)

Template results

Static results

Overriding templates from other apps

The normal template resolution rules apply. Creating eg. templates/web/registration/login.html will override the login page for web only.

Collectstatic

Collectstatic remains unaffected. The collector delegates to finders, so all layer aware resources end up with partial paths under the STATIC_ROOT directory.

Decorators

A user could follow a link that leads him to a layer that serves a broken page. For example a web site is served on www.site.com with an accompanying basic site m.site.com. Visiting www.site.com/flashy-dashboard with a basic device like a Samsung E250 will result in the user being redirected to m.site.com/flashy-dashboard. That page probably does not exist for basic devices because it can’t render it well enough. In such a case a decorator exclude_from_layers is provided that renders a friendly page instead of a 404 or 500 error:

class WebOnlyView(TemplateView):
    template_name = "layers/web_only_view.html"

    @exclude_from_layers(layers=("basic",))
    def get(self, *args, **kwargs):
        return super(WebOnlyView, self).get(*args, **kwargs)

Request based layer lookup

The preferred way of layer lookup is through the presense of an X-Django-Layer header in the request. Django Layers layer lookup is very similar to the site object lookup done in django.contrib.sites. If a layer is explicitly defined in settings then that is used, else the request headers are inspected.

During development you will likely define the layer in your settings file, but in a production environment you don’t want a Django process per layer, so request based lookups are preferred.

Layer objects

The management command load_layers creates a Layer object for each layer in your project. It is useful for doing layer based filtering at database level.

Can I add my own layers?

Yes! Basic, smart and web are just examples. You can define any hierarchy with any names.

Authors

  • Hedley Roos

Changelog

1.11.0

  1. Django 1.11 compatibility.

1.10.1

  1. Fix typos in documentation.

  2. Add layers_collectstatic management command to do layer aware static file collection.

1.10.0

  1. Django 1.10 compatibility.

  2. Make it possible to determine the layer from the request. This removes the need for a Django process per layer.

1.9

  1. Drop Django 1.6 compatibility. Django 1.9 is supported and tested.

0.5.1

  1. Rewrite decorator to be function based because it makes it easier to use in urls.py.

0.5

  1. Provide decorator exclude_from_layers so a view renders properly even if it can’t render for a particular layer.

0.4

  1. Remove redundant collectstatic management command.

0.3

  1. Expand tests.

  2. Fix bug where static file not defined in a layer could not be overwritten in a layer.

  3. Provide a layer aware replacement for collectstatic.

0.2

  1. Inevitable package rename.

0.1

  1. Initial release.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-layers-hr-1.11.0.tar.gz (18.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_layers_hr-1.11.0-py2.7.egg (55.0 kB view details)

Uploaded Egg

File details

Details for the file django-layers-hr-1.11.0.tar.gz.

File metadata

File hashes

Hashes for django-layers-hr-1.11.0.tar.gz
Algorithm Hash digest
SHA256 32ab3062411de3daa2c609b4b9c36939cfdc05fb19256657fb47e4f37228f251
MD5 2daa08e7b857131cdc588a6266138031
BLAKE2b-256 310064441dd1ee5ae941e2e31d8f7396a8b28b5102332068e1f96073d361be9c

See more details on using hashes here.

File details

Details for the file django_layers_hr-1.11.0-py2.7.egg.

File metadata

File hashes

Hashes for django_layers_hr-1.11.0-py2.7.egg
Algorithm Hash digest
SHA256 64bb5538c80d2ba0b2d2cdd19794c953a9a766bf75b4165f3082739356f7d1b7
MD5 c34481316dc5e3f3101adba433594ff2
BLAKE2b-256 9bb3a862eb6b6ad0bc4b90c9e3d091b98e2788bbe7dcc2cecabbf2ffee21601c

See more details on using hashes here.

Release history Release notifications | RSS feed

1.11.1

2 files

This release

1.11.0 This release

2 files

1.10.1

2 files

1.10.0.0

2 files

1.10.0

2 files

1.9

2 files

0.5.1

2 files

0.5

2 files

0.4

2 files

0.3

2 files

0.2

2 files

0.1

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page