I am developing the mobile version of my website, so thought of using user-agent as the criteria for serving different templates for mobile and web version. I successfully read the user-agent information from nginx and passed it as header to gunicorn server.
Then I created a middleware which reads this header and changes the templates directory in settings file. This seemed to work initially but then I realized that there is race condition happening as this method is not thread safe. (I should have thought of it before-hand).
So I started thinking of other alternatives. One solution was to overwrite the render method of django to include "dirs" parameter based on request header. But then I found out that the "dirs" parameter is deprecated. Following is the reference link https://docs.djangoproject.com/en/1.9/_modules/django/shortcuts/#render So even this will not work.
Another solution is to have different template names for mobile and web and load them accordingly. However I don't want to do this and want to keep the templates directory structure exactly same for both web and mobile.
There has to be a way to just overwrite the template directory. This will give me an advantage of falling back on web version of templates if its missing in mobile templates directory.
Any advise on how to achieve this will be helpful.
This is how my templates are organized.
App1
templates
App1
index.html
catalog.html
App2
templates
App2
about.html
And in the project directory(not part of the app folder), there is a mobile templates folder which has the following structure
mobile-templates
App1
index.html
App2
about.html
Thanks Anurag
Here's how I would organize my templates:
templates
dir - mobile
and desktop
.mobile
dir and desktop templates in desktop
.This way you won't have to rename the templates.
And here's how I would render them:
Read User-Agent in a middleware.
Set an attribute on request
called template_prefix
whose value will either be mobile
or desktop
, depending on the User-Agent. Eg:
def process_request(self, request):
# read user agent and determine if
# request is from mobile or desktop
# ...
if mobile_user_agent:
request.template_prefix = 'mobile'
else:
request.template_prefix = 'desktop'
In your views, use request.template_prefix
before template names. Eg:
def home(request):
...
template = request.template_prefix + '/home.html'
return render(request, template)
This will render the templates from either mobile
or desktop
dirs depending on the value template_prefix
attribute.
UPDATE (according to question edit):
Looking at how your templates are organized, I'd do this:
Middleware:
Only set template_prefix
for mobile requests.
def process_request(self, request):
if mobile_user_agent:
request.template_prefix = 'mobile-templates'
else:
request.template_prefix = '' # set an empty string
Views:
Use os.path.join
; catch TemplateDoesNotExist
exception.
import os.path
from django.template.loader import get_template
from django.template.base import TemplateDoesNotExist
def index(request):
try:
template = os.path.join(request.template_prefix, 'App1/index.html')
get_template(template)
except TemplateDoesNotExist:
template = 'App1/index.html'
return render(request, template)
I've tested this and it works. But writing a try...except
block in every view seems redundant. If I come up with a better solution, I will update.