How to use different templates for different sites/domains

47 views
Skip to first unread message

Antonis Christofides

unread,
May 28, 2024, 8:58:14 AMMay 28
to Django users
Hello,

I use the sites framework for a Django project that serves many different domains. But each of those domains has some templates overridden.

If I used a different instance of Django (i.e. a different gunicorn service) for each domain, I'd have different settings for each site. But I'm using a single instance to serve all sites and, wherever I need to, I use things that extract the domain from the request, like `get_current_site()`. But this doesn't seem to work with templates. A custom template loader won't work without a fight because its methods don't accept the request object as an argument.

All solutions I've thought about are ugly hacks. The least ugly seems to be to create middleware that stores the request object in a contextvar. But it strikes me that I can't find a simpler solution for this. Is what I want that uncommon, or am I missing something?

There's an old closed "wontfix" ticket about this but without adequate explanation.

Mike Dewhirst

unread,
May 28, 2024, 8:53:27 PMMay 28
to django...@googlegroups.com
On 28/05/2024 9:09 pm, Antonis Christofides wrote:
Hello,

I use the sites framework for a Django project that serves many different domains. But each of those domains has some templates overridden.

Might depend on what you are overriding - entire templates or just includes or just vars.

I would probably start by refactoring the templates so they were identical for all sites and reduce/extract the differences to includes which can be selected via contextvars after calling get_current_site() from the view.

Have you looked at template tags?

I use them for displaying additional information on the staging and dev sites versus production. Not what you are doing so I haven't thought too hard about that. Only worth a thought if you haven't considered it.



If I used a different instance of Django (i.e. a different gunicorn service) for each domain, I'd have different settings for each site. But I'm using a single instance to serve all sites and, wherever I need to, I use things that extract the domain from the request, like `get_current_site()`. But this doesn't seem to work with templates. A custom template loader won't work without a fight because its methods don't accept the request object as an argument.

All solutions I've thought about are ugly hacks.

Practicality beats purity

The least ugly seems to be to create middleware that stores the request object in a contextvar. But it strikes me that I can't find a simpler solution for this. Is what I want that uncommon, or am I missing something?

There's an old closed "wontfix" ticket about this but without adequate explanation.
--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/175b4601-2038-479b-9581-48d9c196df7cn%40googlegroups.com.


-- 
We recommend signal.org

Signed email is an absolute defence against phishing. This email has
been signed with my private key. If you import my public key you can
automatically decrypt my signature and be sure it came from me. Your
email software can handle signing.
OpenPGP_signature.asc

Faisal Mahmood

unread,
May 29, 2024, 6:49:22 AMMay 29
to django...@googlegroups.com

You're right, using a single Django instance to serve multiple sites with overridden templates can be tricky. While a custom template loader might seem appealing, it's true that it doesn't accept the request object by default. Here's the breakdown and some alternative solutions:

The Challenge:

  • Django's default template loader doesn't consider the current domain when searching for templates.
  • You want to use a single Django instance but have domain-specific templates.

Less Ugly Solutions:

  1. Template Name Prefixing:

    • Prefix your template names with the domain name. For example, domain1/home.html and domain2/home.html.
    • In your views, construct the full template name based on the current domain (using get_current_site).
    • This approach is simple but can make template names lengthy and less readable.
  2. Template Inheritance with Context Processors:

    • Create a base template with common elements.
    • Inherit from the base template for each domain-specific template.
    • Use a context processor to inject the current domain information into the context.
    • In your domain-specific templates, use the domain information to conditionally render specific content.
    • This approach offers flexibility but requires more code in templates and context processors.
  3. Third-Party Packages:

    • Consider packages like django-sites-templates or django-multihost-template-loader.
    • These packages provide custom template loaders that can leverage the request object to determine the appropriate template based on the domain.
    • This approach can be a good option if the built-in solutions don't meet your needs.

Middleware with Context Variables (Least Ugly Hack):

  • While not ideal, storing the request object in a context variable using middleware is a workable solution.
  • However, be mindful of potential issues like variable name conflicts and unnecessary data passed to every template.

Choosing the Best Approach:

The best solution depends on your project's complexity and preference. Here's a quick guide:

  • Simple Projects: Template Name Prefixing might suffice.
  • More Complex Projects: Consider Template Inheritance with Context Processors or Third-Party Packages for better maintainability.
  • Last Resort: Use the Middleware approach cautiously if other options aren't feasible.

Remember, the key is to find a balance between simplicity and maintainability. Leverage built-in features and explore third-party packages before resorting to complex hacks.

I'm available if you want further assistance or questions about it😎

Have a good day ahead. 


Reply all
Reply to author
Forward
0 new messages