Package: django-layers-hr
Django LayersTravisDjango Layers makes it possible to serve a set of templates and
static resources as defined insettings.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 createfoo.htmlfor basic devices it is
automatically available for desktop browsers as well. You can overridefoo.htmlfor desktop browsers.InstallationInstall or adddjango-layers-hrto your Python path.Addlayersafterdjango.contrib.staticto yourINSTALLED_APPSsetting.Ensure the app that you will be creating layers for appears first inINSTALLED_APPSelse template override won’t work.ExampleNote: there is a working example in theexamplesubdirectory.We have sites example.com, basic.example.com and smart.example.com. Each
of the sites have their ownsettings.py, thus different Django
processes.Directory structuretemplates
    - 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)SettingsWe 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 thecurrentkey 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 defaulttreeformat.Desktop settings hasLAYERS = {'layers': ['basic','web']}.Basic settings hasLAYERS = {'layers':['basic']}.Smart settings hasLAYERS = {'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 resultshttp://example.com/fooyields (1).http://example.com/baryields (4).http://basic.example.com/fooyields (1).http://basic.example.com/baryields (2).http://smart.example.com/fooyields (1).http://smart.example.com/fooyields (3).Static resultshttp://example.com/static/foo.cssyields (5).http://example.com/static/bar.cssyields (8).http://basic.example.com/static/foo.cssyields (5).http://basic.example.com/static/bar.cssyields (6).http://smart.example.com/static/foo.cssyields (5).http://smart.example.com/static/foo.cssyields (7).Overriding templates from other appsThe normal template resolution rules apply. Creating eg.templates/web/registration/login.htmlwill override the login page
for web only.CollectstaticCollectstatic remains unaffected. The collector delegates to finders, so
all layer aware resources end up with partial paths under theSTATIC_ROOTdirectory.DecoratorsA 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
decoratorexclude_from_layersis 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 lookupThe preferred way of layer lookup is through the presense of anX-Django-Layerheader in the request. Django Layers layer lookup is very
similar to the site object lookup done indjango.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 objectsThe management commandload_layerscreates aLayerobject 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.AuthorsHedley RoosAltus BarryChangelog1.11.1Guard against KeyError, when request is empty in get_current_layer_stack().1.11.0Django 1.11 compatibility.1.10.1Fix typos in documentation.Addlayers_collectstaticmanagement command to do layer aware static file collection.1.10.0Django 1.10 compatibility.Make it possible to determine the layer from the request. This removes the need for a Django process per layer.1.9Drop Django 1.6 compatibility. Django 1.9 is supported and tested.0.5.1Rewrite decorator to be function based because it makes it easier to use in urls.py.0.5Provide decoratorexclude_from_layersso a view renders properly even if it can’t render for a particular layer.0.4Remove redundant collectstatic management command.0.3Expand tests.Fix bug where static file not defined in a layer could not be overwritten in a layer.Provide a layer aware replacement for collectstatic.0.2Inevitable package rename.0.1Initial release.