How to make Django support multiple domains with one settings.py? - python

We want one Django instance to serve different domains. The only difference between them is different templates, all the rest is the same. So we tried to just modify TEMPLATES.DIRS in a middleware. But Django templates loader ignores all the changes in TEMPLATES.DIRS made after settings.py is loaded.
Is there more or less standard Django Way to support different TEMPLATES.DIRS for different domains with just one settings.py?

To solve your problem use a template variable, both extend and include support variables. Just omit the quatation marks:
{% extends "base.html" %}
becomes
{% extends string_variable_with_file_name %}
Of cause you have to set that variable to the right filename in your context.

Related

Define multiple templates for a predefined block wagtail CRX

I was moving a site over to wagtail and decided to use the codered extensions. The library comes with a image-gallery content-block. I want to use this but define a few templates you can choose from in the admin UI.
You usually define a template in the meta section, but I noticed a dropdown in the admin UI for a template.
How do I add a template to that dropdown? Link to the content block I want to change
I am interested in adding an HTML template and not inheriting from the content-block to change behaviour. (Unless inheriting is the only way to add a template to the dropdown.)
You could paramatise the path to the template you want to use then use an include in your block template to point to the chosen one.
For example, if you had a card block with selection for vertical or horizontal format. In your card block class you might have an property named template that uses a choice block, something like
class AlignmentChoiceBlock(ChoiceBlock):
choices=[
('blocks/flex/vertical_card.html', 'Vertical'),
('blocks/flex/horizontal_card.html', 'Horizontal')
]
Then in your block template, it just consists of:
<div class="some-block-container">
{% include value.template %}
</div>
Well, this works for Wagtail at least, not sure about codered.
The answer from Richard Allen works wagtail and is perfect for your own blocks etc. Wagtail blocks define a separate field that is used for their included components, for this you need another approach.
First you need to add the CRX_FRONTEND_TEMPLATE_BLOCKS to your django settings mysite/settings/base.py.
Then create a folder for your block templates in mysite/website/templates and create a custom template. Then add this path as a entry to the CRX_FRONTEND_TEMPLATE_BLOCKS. Entry key should be the block in lowercase. For a starter you could copy a template/html file from the codered package, found in coderedcms/blocks/
Now the template should be available from the template dropdown under the advanced menu of a crx block.
This info came from a gh issue of crx. This is e pretty recent addition and the dev mentioned that they are looking to make this easier. So this might change in the future, this worked for me on 26/01/2023.

Advice about composing several django templates

I'm developing a web application with Django and we have met a dilemma about the design.
We were making one template for every screen, but right now we have detected that some parts of of the screen with the information are repeated all over the different screens. For example, when coming to show personal data of a person, you can show also another data concerning that person, but not personal data (financial data, for instance).
My intuition told me that we should look for a solution in which we could make small templates that we could compose, combine and concatenate and that we should also make different views or functions which would return its own associated template each one.
Thus, person_data() would return the rendered template showing the name, surname, address, etc... and financial_data() would return the rendered template showing the salary, bank account, etc... After that, the desirable thing would be concatenating both or inserting them in a wider template for showing all this together.
<html>
...
{# Html code here #}
...
{# person_data template #}
...
...
{# financial_data template #}
...
{# Html code here #}
...
</html>
So as always I made some research on the net and I found:
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#include
a link which describes how to use include for inserting a template file in another template:
{% include "foo/bar.html" %}
And you can also use a variable from the python function with the path name or an object with render method:
{% include template_name %}
So we could use all this in this way for combining, concatenating, composing and operating on templates. We could choose the one which includes the others and passing it the context for all templates (I suppose, I didn't test anything). But I don't know if I'm well directed or if this is the best way to go. I would appreciate some advice.
I also found another interesting thread in stackoverflow talking about this:
How do you insert a template into another template?
My idea is to have small templates which are used repeatedly in different spots of the web and composing them in Unix-like style, so I would have small visual pieces that would be used once and again saving a lot of hours of writing of code.
Please some advice.
Thanks in advance
Yes, that is a correct approach. I think the best solution is to combine {% include %} and {% extend %}, which will allow you to inherit from a base template (via extend), and include parts you want from other templates (via include).
You'd end up having a base template, a template for the header, the footer, parts of the body etc.
You might also want to read more about it here and here

Achieve different behaviour when accessing from other domain

I have a website running Django whose main domain is example.com. What I want to achieve is to behave in a different way when an user access from example2.com (specifically loading custom CSS).
I understand that I have to make some changes to the web server and that is not a problem. My question is focused on how to accomplish this with Django.
There is something called Django sites that could be useful for this, but I am not sure if this is an overkilling feature for such a "simple" thing. However I am aware that multiple changes would be needed (paths, cookies domain, etc), so... is this the recommended way to do it?
It's a pretty simple thing to accomplish. You have a few different options.
Checking the HTTP_HOST straight from a template
A very simple approach would be from a template to check the request.META dictionary's value for the HTTP_HOST key.
{# Anything other than port 80, HTTP_HOST will also include the port number as well #}
{% ifequal request.META.HTTP_HOST 'example2.com' %}
<!-- your css imports here -->
{% endifequal %}
Remember, this is set by the client though, so if you were doing anything else that was security-sensitive, this would NOT be the approach to use. Just for loading some CSS though, it would be fine.
Custom middleware
Another option would be to create custom middleware and check this same object from there. Basically the same process but you'd probably want to do something like set an extra key on the request object
In some file.. yourproject/someapp/middlware.py
class DomainCheckMiddleware(object):
def process_request(self, request):
if request.META['HTTP_HOST'] == "example2.com":
request.IS_EXAMPLE2 = True
else:
request.IS_EXAMPLE2 = False
return None
In your settings.py
MIDDLEWARE_CLASSES = (
# whatever middleware you're already loading
# note: your middleware MUST exist in a package that's part of the INSTALLED_APPS
'yourproject.someapp.DomainCheckMiddleware'
)
In your template
{% if request.IS_EXAMPLE2 %}
<!-- load your css here -->
{% endif %}
This is more legwork, and pretty much does the same thing, but you could easily apply some extra tests to see if you're in debug mode or just accessing over localhost:8000 and still set IS_EXAMPLE2 to true, without making your templates more difficult to read.
This also has the same downfall mentioned previously.
https://docs.djangoproject.com/en/dev/topics/http/middleware/
Using the sites framework
Using the sites framework is only valid if you have enabled it (django.contrib.sites) enabled, which it no longer is by default and is overkill for your purposes. You can see an example of how that would work from this answer though:
How can I get the domain name of my site within a Django template?

Is there any way to restrict the use of tags and filters in Django templates?

I know Django has already a good templating system for designers but I wonder if it is possible to limit the usage of certain template tags and filters.
We are building a Django plugin for designers to make template developing more open, but we want to hide some logic of django template system and expose just the necessary to the designer.
In example: How can I prevent the use of {% load %} template tag and preload only the tags that I want?
Try this decorator: Safe template decorator
From author description:
A decorator that restricts the tags and filters available to template
loading and parsing within a function.
This is mainly meant to be used when granting users the power of the
DTL. You obviously don't want users to be able to do things that could
be potentially malicious.
The {% ssi %} tag, for example, could be used to display sensitive
data if improperly configured.
{% load %} gives them access to all the unlimited python code you
wrote in your templatetags. {% load sudo %}{% sudo rm -rf / %} o_0
Note that the "load" tag (among others) is not listed in the default
tag whitelist. If you parse a template (however indirectly) in a
function decorated with this, unlisted builtin tags will behave like
undefined tags (ie, they will result in a TemplateSyntaxError).
Since {% load %} is not whitelisted, you may want to include some
custom tags or filters as "builtins" for convenience. Simply put the
module paths to the libraries to include in the extra kwarg or the
extra_libraries list. Generally, this is not recommended, as these
libraries need to be carefully and defensively programmed.
NOTE: This does not do anything about cleaning your rendering context!
That's completely up to you! This merely restricts what tags and
filters are allowed in the templates.
Examples:
from django.template.loader import get_template
safe_get_template = use_safe_templates(get_template)
tmpl = safe_get_template('myapp/some_template.html')
from django.template import Template
use_safe_templates(Template)('{% load sudo %}')
# TemplateSyntaxError: Invalid block tag 'load'
An easy way would be to implement your own template loader similar to Django's file system loader and strip certain tags out of the text (guess you could event turn into a template/template nodes when doing so to be able to parse it correctly) before giving the template to Django for further processing.

Django Loading Templates with Inheritance from Specific Directory

In our project, we have a bunch of different templates that clients to choose from (for their webstore). The file layout is something like this:
templates
cart.html
closed.html
head.html
standard
bishop
default
indiana
marley
mocca
nihilists
raconteurs
tripwire
Every subfolder of standard contains a few template files like base.html, browse.html and item.html. Browse and Item inherit from base.
What I want to do is render the browse template in a specific template folder (let's say templates/standard/bishop) isolated from any other global template path settings in my app. Is there a way to do that?
UPDATE: I'll try to be more clear. If I just render browse.html from the bishop subfolder it tries to extend base.html and it can't find it. I could alter the settings template path to include the bishop folder, but I'm looking for a way to make it work leaving that alone.
In your templates/standard/bishop/browse.html template you're doing the following:
{% extends "base.html" %}
This refers to templates/base.html and not templates/standard/bishop/base.html. By default Django will check your installed applications as well as the template directories that you specified under TEMPLATE_DIRS in settings.py.
This behavior is specified by TEMPLATE_LOADERS in settings.py:
http://docs.djangoproject.com/en/dev/ref/settings/#template-loaders
http://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types
You might be able to get away with what you're trying to do by creating your own template loader, otherwise simply specify the actual path to base.html:
{% extends "standard/bishop/base.html" %}

Categories

Resources