[Answered ]-Dynamically serve static content based on server name in Django

1👍

Not sure how to do simple rewrite rule in nginx. Aside from a template tag (if you are only swapping out static content, then I think a template tag is the way to go), if the sites are gonna be different at all, template-wise, you can handle it by writing a custom template loader.

This allows you to pick what templates you would like to use when you render your page. This method has a graceful way of failing if the loader fails to find a matching template for your specific domain. If it doesn’t find a match, it will fall back to your main templates directory. So you could have custom stuff for some domains, and more generic for others.

But to make a decision what to serve based upon a request header, you’ll need to make the request available to the loader via _thread_locals, I do this in some middleware:

#custom.middleware.py
try:
    from threading import local
except ImportError:
    from django.utils._threading_local import local

_thread_locals = local()

def get_current_request():
    return getattr(_thread_locals, 'request', None)

class RequestMiddleware():
    def process_request(self, request):
        _thread_locals.request = request

Next write a template loader (update the path to your middleware):

#custom.loaders.py
from os.path import join
from django.conf import settings
from django.template import TemplateDoesNotExist
from path.to.middleware import get_current_request

def load_template_source(template_name, template_dirs=None):
    request = get_current_request()
    host = request.get_host()
    path_to_template_dir = None
    for site in settings.SITE_TEMPLATE_FOLDERS:
        if site[0] == host:
            path_to_template_dir = site[1]
            break

    if path_to_template_dir:
        try:
            filepath = join(path_to_template_dir, template_name)
            file = open(filepath)
            try:
                return (file.read(), filepath)
            finally:
                file.close()
        except IOError:
                pass

    raise TemplateDoesNotExist(template_name)

and lastly update your settings file with three things 1) add the template loader (make sure its listed first) 2) add the middleware 3) and then add a new variable SITE_TEMPLATE_FOLDERS with a tuple of tuples containing domains and paths to template folders:

#settings.py

.....

TEMPLATE_LOADERS = (
    'custom.loaders.load_template_source',
    'django.template.loaders.filesystem.load_template_source',
    'django.template.loaders.app_directories.load_template_source',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'domain.middleware.SessionMiddleware',
    'custom.middleware.RequestMiddleware',
)

SITE_TEMPLATE_FOLDERS = (
    ('mydomain.com', '/path/to/templates'),
    ('myotherdomain.com', '/path/to/other/templates')
)
...

Seems like a lot, but now you can easily add a new domain via your settings file.

1👍

You’re looking for the “sites” framework.

0👍

For example, Apache has mod_rewrite that you can use to rewrite URLs:

RewriteCond %{HTTP_REFERER} ^www.domain1.com$ [NC]
RewriteRule /static/[^/]+ /static/domain1/$1 [L]
RewriteCond %{HTTP_REFERER} ^www.domain2.com$ [NC]
RewriteRule /static/[^/]+ /static/domain2/$1 [L]


(this is untested)

other servers also have similar functionality.

Just make sure your django application emits static urls that are site-independent and can be correctly rewritten.

👤akonsu

Leave a comment