Easy iPhone support for Django apps
Written on 12.12.07
By this time you should already know how easy it is render web pages for the iPhone using Ruby on Rails. I couldn't find anything similar for Django, so I'm going for it. It's really easy stuff and you'll get to keep your view code (at least most of it) intact. Let's start by creating a decorator that does the rendering bits. In the end, the result should be something like:
# -*- coding: utf-8 -*-
from myapp.decorators import response
@response('message.html')
def some_view_func(request):
ctx = dict(message='Hello world')
return ctx
Your view function only needs to return a dictionary (or None but that is somewhat useless) with the values for the template or it can return any of other Django's Http* objects (e.g. HttpResponseRedirect).
Here's the code for the decorator, which should be in the myapp/decorators.py file:
# -*- coding: utf-8 -*-
from django.template import RequestContext
from django.shortcuts import render_to_response
def response(template,*args):
def _process_view(view_func):
def _handle_request(request,*args,**kwargs):
context = view_func(request,*args,**kwargs)
if context is None: context = dict()
if isinstance(context,dict):
return render_to_response(template,RequestContext(request,dict=context))
else:
return context #this is probably a redirect
return _handle_request
return _process_view
Lets extend this bit of code to add support for iPhone people instead of creating a special view. I'm assuming your iPhone templates will be stored in a templates/iphone directory, so you'll have a templates/message.html and a templates/iphone/message.html. Ideally you'll create a subdir for regular web templates too (e.g. templates/web/message.html).
# -*- coding: utf-8 -*-
from django.template import RequestContext
from django.shortcuts import render_to_response
import re
_IPHONE_UA = re.compile(r'Mobile.*Safari')
def is_iphone(request):
return _IPHONE_UA.search(request.META['HTTP_USER_AGENT']) is not None
def response(template,*args):
def _process_view(view_func):
def _handle_request(request,*args,**kwargs):
context = view_func(request,*args,**kwargs)
if context is None: context = dict()
if isinstance(context,dict):
path = is_iphone(request) and 'iphone' or 'web'
return render_to_response('%s/%s' % (path,template),RequestContext(request,dict=context))
else:
return context #this is probably a redirect
return _handle_request
return _process_view
Using and slightly extending the original response decorator you'll be able to keep everyone happy without having to create special views just for iPhone users.