Theming

49 views
Skip to first unread message

Clinton Blackburn

unread,
Apr 7, 2017, 7:30:13 PM4/7/17
to Django users
Has anyone solved site-aware theming? I have a multi-tenant site (using sites framework) and I want to render custom templates for each site. My current design calls for a default design, and overrides of the base template (or child templates) for each site. Obviously, I can achieve the overrides by prepending the site/theme name when I include a template/static file. However, this does not allow for easy support of a default fall-back.

How have others solved this problem? Are you using thread.local/global variables, as I've seen in some locations?

Are there any plans to support a request/site-aware template loader?

Thanks,

Clinton

Russell Keith-Magee

unread,
Apr 8, 2017, 5:44:17 AM4/8/17
to Django Users
On Sat, Apr 8, 2017 at 1:28 AM, Clinton Blackburn <clinton....@gmail.com> wrote:
Has anyone solved site-aware theming? I have a multi-tenant site (using sites framework) and I want to render custom templates for each site. My current design calls for a default design, and overrides of the base template (or child templates) for each site. Obviously, I can achieve the overrides by prepending the site/theme name when I include a template/static file. However, this does not allow for easy support of a default fall-back.

Actually - it does.

Any time you specify a template to render, you can also specify a *list* of templates. So, you can do something like this:

def my_view(request):
    …
    return render(request, [
            ‘path/to/template/%s/template.html’ % user_theme,
            ‘path/to/template/default/template.html’,
        ], {…context…})

That will pick the user’s theme by default; if the user’s theme doesn’t specify a given template, or the user doesn’t have a theme (or the user’s theme is set to default), it will use the default theme directory.

Hope that helps!

Yours,
Russ Magee %-)
 
How have others solved this problem? Are you using thread.local/global variables, as I've seen in some locations?

Are there any plans to support a request/site-aware template loader?

Thanks,

Clinton

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/8aaf04dc-2de7-4972-8ae5-aaaefa2bf17f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Clinton Blackburn

unread,
Apr 8, 2017, 10:05:11 AM4/8/17
to Django users
Russ,

How would this work for base/nested templates? Say my view is rendering the potential templates ['my-theme/page.html', 'page.html'], and the templates inherits base.html. Do I have to override base.html for every theme if I want base.html (or any other child/parent template) to be theme-able? Is there a version of {%include%} that takes an array, or will I need to write my own tag?

I would like to avoid duplicating templates unnecessarily (e.g. every theme has to have all of the templates, even if there is no override) if possible. So far I see my options as either duplicating templates or writing a custom {% include %} tag that is theme-aware.

Thanks,
Clinton


On Saturday, April 8, 2017 at 5:44:17 AM UTC-4, Russell Keith-Magee wrote:
On Sat, Apr 8, 2017 at 1:28 AM, Clinton Blackburn <clinton....@gmail.com> wrote:
Has anyone solved site-aware theming? I have a multi-tenant site (using sites framework) and I want to render custom templates for each site. My current design calls for a default design, and overrides of the base template (or child templates) for each site. Obviously, I can achieve the overrides by prepending the site/theme name when I include a template/static file. However, this does not allow for easy support of a default fall-back.

Actually - it does.

Any time you specify a template to render, you can also specify a *list* of templates. So, you can do something like this:

def my_view(request):
    …
    return render(request, [
            ‘path/to/template/%s/template.html’ % user_theme,
            ‘path/to/template/default/template.html’,
        ], {…context…})

That will pick the user’s theme by default; if the user’s theme doesn’t specify a given template, or the user doesn’t have a theme (or the user’s theme is set to default), it will use the default theme directory.

Hope that helps!

Yours,
Russ Magee %-)
 
How have others solved this problem? Are you using thread.local/global variables, as I've seen in some locations?

Are there any plans to support a request/site-aware template loader?

Thanks,

Clinton

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.

Russell Keith-Magee

unread,
Apr 8, 2017, 11:27:19 AM4/8/17
to Django Users
Hi Clinton,

On Sat, Apr 8, 2017 at 4:05 PM, Clinton Blackburn <clinton....@gmail.com> wrote:
Russ,

How would this work for base/nested templates? Say my view is rendering the potential templates ['my-theme/page.html', 'page.html'], and the templates inherits base.html. Do I have to override base.html for every theme if I want base.html (or any other child/parent template) to be theme-able? Is there a version of {%include%} that takes an array, or will I need to write my own tag?

The template loading list (i.e., [‘my-theme/page.html’, ‘page.html’]) indicates which template will be rendered. Each of those template can, themselves, include or extend any other template they want. So, ‘my-theme/page.html’ could extend ‘page.html’, which could, in turn, extend ‘base.html’ - or both templates could directly extend ‘base.html’. 

The argument that is passed to {% extends %} is also something that can be paramterized - so, for example, you can pass in a variable as template context that contains the “parent” template - so you could do something like having “page.html” that starts “{% extends theme %}”, and then pass in {“theme”: “path/to/theme.html”} as context.

The same applies to {% include %} - anywhere that you pass in a string in a template could, potentially, be a variable.

The approach that will work best depends on exactly what “theming” means in your context. 

Is it the same basic structure that just has a different style sheet? Then having a template with {% include theme %} will probably be best.

Or is it a base structure where key bits of content are different? In that case, having a my-theme/page.html that extends page.html, and using the template loader trick will probably be best.

Or are the same *pieces* on each page, but laid out differently for each user?  In that case, you probably want a page.html that starts with {% extends theme %}, so that the theme establishes basic page structure, and the page defines the blocks that are placed into that structure.

Yours,
Russ Magee %-)
 

Clinton Blackburn

unread,
Apr 26, 2017, 9:02:06 AM4/26/17
to Django users
Russ,

Thanks for your help. I ultimately abandoned the (over-engineered) nested idea. Since we were on a tight deadline, I decided to focus only on the one page I needed customized. The template has three sections—header, body, footer. I use select_template to find the right templates to include in these sections.


Ultimately, I think I want to migrate to something similar to https://github.com/moorinteractive/wagtail-themes/. While it uses thread locals (of which I am not a fan), it ultimately allows for the entire site to be themed without having to customize every view/template.

Thanks again,
Clinton Blackburn
Reply all
Reply to author
Forward
0 new messages