Change django template search path depending on request - django

For my application I want to serve a different base.html (and other templates and static files) for visitors and for admins: visitors will see a customized themed frontend, admins will see the editor interface (not related to the django admin interface). Some templates / resources will be shared between the two frontends.
I know I can do this by having separate settings.py configurations and include different template paths in each of them through a django app, but that would also mean I have to run two instances of the app. I'd rather serve both frontends from a single instance (or pool of workers).
Is there a way to dynamically add extra folders to the Django search path? That should suit my needs: if the user comes through the visitor domain, search the added path first and then the defaults, else just use the default template search path.

This is exactly why I've created django_layers
It's inspired by the Plone skinning/layer system where you can switch skins and have the framework search different layers for templates, staticfiles, and so on. I was missing something similar in Django where, like you, the only option I could find was inheritance or distinct INSTALLED_APPS configurations.
It turns out it's also very suitable for other use-cases such as A/B testing.
The packages is relatively new, let me know if it works for you or if you have issues if you decide to use it.

You can leverage template inheritance for this purpose, especially the {% extends %} template tag, which can accept variables instead of literal strings.
Example:
In your child templates make them extend unknown base template like this:
{% extends BASE_SITE_TEMPLATE %}
{% block page_head %}
<!-- Custom per-page static files may be defined here -->
{% endblock %}
{% block page_content %}
...
{% endblock %}
And then write a template context processor that will pass the BASE_SITE_TEMPLATE variable based on your custom conditions to rendered templates:
def base_site_template(request):
# Here goes your conditions to select proper base template, for example
# by checking request.user permissions or some other logic.
...
return {'BASE_SITE_TEMPLATE': ...}
Of course You will need to define various base templates, like base_site_user.html, base_site_editor.html, base_site_admin.html.
This method doesn't require you to change any of your views, just child templates, so I think it's one of the simplest methods to do what You want.

Related

How to use a base.html for default Wagtail Page instance?

Wagtail starts new projects with a single welcome template. However, this template does not inherit from any parent template, such as a base.html. In our project, we have previously defined a base.html containing global HTML tags and CSS/JavaScript includes.
How can we tell the default Wagtail Page model to display in a template that extends base.html?
To clarify, there are two possible setups, depending on how you create your project:
If you start a new project from scratch with wagtail start myproject, the initial migrations (which exist partly within Wagtail itself, and partly within the project template) will set you up with a HomePage model and an initial homepage. The template for this page type lives at home/templates/home_page.html, and is already set up to inherit from a base template (which lives at myproject/templates/base.html).
If you follow the documentation for integrating Wagtail into an existing Django project, the initial migrations (which in this case are entirely within Wagtail) will give you an initial page of type wagtailcore.Page. You're not really expected to use this page type directly (not least because it has no fields beyond the title, and no way of adding new ones) - it's only done this way because there are no "proper" page models set up yet, and there needs to be something as the initial state of the page tree. The idea is that once you've set up at least one page model within your app, you can create your real homepage, point the Site record at it (in Settings -> Sites), and delete the initial stub one.
Nevertheless, if you really want to give wagtailcore.Page a full-fledged template with a base template, you could create a template file inside one of your project's apps at the path templates/wagtailcore/page.html. As long as the app in question is above 'wagtail.core' in the INSTALLED_APPS list, this will override the barebones template supplied by Wagtail.
{% extends "base.html" %}
Add that to your template, it will extend anything in the base.
If your base template has blocks in it, you use the same syntax
{% block content %}
This will appear wherever you have this same block in the base.html template
{% endblock %}
Wagtail is built on top of Django, you can read more about its templating language here: https://docs.djangoproject.com/en/3.0/ref/templates/language/

Subrequests in Django templates

I'm working on my first Django project and have my templates setup with a base that all the others extend. In that base I want to have some user-specific navigation which means loading some values from the database to build the contents of a drop down menu. However I don't want to have to do this inside each view. Coming from Symfony2/Twig I would normally do this using a sub-request where I tell the template to render a view and that will use it's own template. Using syntax like:
{% render 'Bundle:Controller:action' with {} %}
How would I accomplish this same thing with Django? I've read over the docs a couple of times but can't find any way to do this.
You have two approaches:
(better)
- add the code to base.html (the one you're always extending) and only override it when you need to.
or
(worse)
- in every template use {% include %} to include your menus.html template.
Update: re-reading your question: you could modify the request in context-processor so your base.html would then have this information.
Custom template tags are what you want.

How to conditionally skin an existing site (for partner branding)

I've got an existing Django site, with a largish variety of templates in use. We've agreed to offer a custom-skinned version of our site for use by one of our partners, who want the visual design to harmonize with their own website. This will be on a separate URL (which we can determine), using a subset of the functionality and data from our main site.
So my question is: what's the best way to add reskin functionality to my site, without duplicating a lot of code or templates?
As I see it, there are several components which need to work together:
URL: need to have a different set of URLs which points to the partner-branded version of the site, but which can contain all the standard path info the site needs to build pages.
Template 'extends': need to have the templates extend a different base, like {% extends 'partner.html' %} instead of {% extends 'base.html' %}
View logic: need to let the views know when this is the partner-branded version, so they can change the business logic appropriately
My idea so far is to put the partner site on a subdomain, then use a middleware to parse the domain name and add 'partner' and 'partner_template' variables to the request object. Thus, I can access request.partner inside my views, to handle business logic. Then, I have to edit all my templates to look like this:
{% extends request.partner_template|default:'base.html' %}
(According to this answer, 'extends' takes a variable just like any other template tag.)
Will this work properly? Is there a better way?
If you are using different settings.py for the different sites you can
specifiy different template loading directories. (Which may default to your unskinned pages.)
Personally I'm not convinced by having different business logic in the same view code, that smells like a hack to me - the same as extensive conditional compilation does in C.
So to sum up.
Use django.contrib.sites and different settings.py
Get a clear idea, how much this is a new app/website using the same data, or just different css/templates.

CMS subsites with Django

I'm using Django to create a site that provides a separate web UI for sorts of producers and consumers. Both UIs (or "subsites") have different layouts, menus and graphics. However they access the same database and models, just from different aspects (producer vs. consumer...).It's all hosted under a single domain, the UI differentiation is done with URLs.
The problem comes when I want to integrate a CMS to this system, to take care of the menu structures and textual content. How should I go about handling the two different menus for the different UIs? I took a look at django-cms and django-page-cms, and they seem to maintain only a single menu hierarchy.
Any ideas?
One dirtyish solution would be to add e.g. a different prefix for each UI's menu items in the CMS, and hack the CMS code so that it only inserts the menu items for the correct UI (given as a parameter to the show_menu template tag).
A nicer way would be if it was possible to have multiple instances of the CMS app, so that each of them had their own database tables as well. But is this possible with django and e.g. django-cms or django-page-cms?
Some further restrictions:
the CMS must support localization
I'd prefer running a single Django instance, to keep the configuration and testing simple
I have not used django-cms so this is just off the top of my head.
There's a section of the docs called Extending the menu that looked promising. It may be unfortunate that so much of their configuration is in settings.py because it looks like you could manipulate their CMS_TEMPLATES to use different base templates (etc.) for different users. One way of getting around this (assuming that there is not a more direct route) is to add something to the UserProfile that identifies a user as consumer/producer. Then in your base.html you do:
{% if user.get_profile.consumer %}
...
{% else %}
...
{% endif %}
This effectively gives you two entirely different look/feel options based on user type. I'll also note that {% extends %} can take either a string constant or a string variable, so you could use a context_processor to set the name of template you are extending.
What you need is show_menu_below_id tag of django-cms. Create the pages consumers and producers with their respective id (advanced fieldset, on bottom of the page form) and then start building the page hierarchy for each one.
Then in the templates uses the tags:
<ul>
{% if user.get_profile.consumer %}
{% show_menu_below_id "consumer" %}
{% else %}
{% show_menu_below_id "provider" %}
{% endif %}
</ul>

template django

how can i use different template in different application.in a project i have two app 1)Site 2)Ad .I want to use default template in Ad but different in Site..How to ?OR in the template is there is a way to use 'if condition' as i have to change only two lines in the templates.
First of all, you are never bound to use same template in different application. Different apps can use different templates, as common practice these days are to place template directories in respective app folder.
Moreover, for change of two lines, you can alwayz use `
{% if condition %}
something
{% else %}
some other thing
{% endif %}
or
{% ifequal var 'var' %}
something
{% else %}
some other thing
{% endifequal %}
All in same template.
Edit
If you say you want to use same templates in diff applications, you can apply path of template considering the facts that,
firstly django template loader will look for a template in same app directory,
then in projects's root directory, and if not found, it will look for it django's own template source.
So if you want to use template anywhere, you can place them in a folder called templates, placed in the same path where your apps directories are. (i.e. root of the project).
projectroot/app1/templates/app1.html
projectroot/app2/templates/app2.html
projectroot/app3/
projectroot/templates/common.html
likewise common.html can be available to all apps.
Use template inheritance http://www.djangobook.com/en/1.0/chapter04/ Define a base template and change only the desired block.
Pl. check the links to the question I had raised for which the answer is provided by Yuji T
How to use 2 different change_list.html for 2 applications in the same django project