If you've ever looked into creating your first Django project targeted at mobile devices, you were probably quick to realize that there is no be all, end all solution. Mobile development decisions have to be made with regards to handheld device detection, redirects, how to deal with desktop vs. mobile content, and so on. Your own requirements will have to dictate how you approach these decisions.

Hopefully, by explaining the mobile development goals we established at Imaginary Landscape and the steps taken to meet them, you can use this information as a foundation for your own mobile website built with Django. We'd love to hear any comments and suggestions as well.

Mobile Development: Server Setup

The first thing we considered was in which layer to handle mobile device detection. We decided we would be using an m. subdomain and wanted the redirect to occur automatically for a mobile user upon first visiting the site. Because of this, it made sense to put both the detection and redirects in the server configuration. In our case it was Nginx but using the same principles, it's simple in Apache as well. In some ways it's simpler. If you are using Apache, you can check out something like the Apache Mobile Filter which utilizes WURFL (Wireless Universal Resource File), eliminating the need to spell out the mobile user agents within your server configuration.

Linking Between the Mobile Site and Full Site

On our mobile site, we would have a link back to the full site that would simply contain a query string, allowing the server to rewrite back to the same page on the desktop version. The detection of this query string would set a cookie to avoid redirection back to mobile site for the duration of the session.

<a href="?full">Full Site</a>

Conversely, the full site would use the same method to link back to the mobile version.

<a href="?mobile">Mobile Site</a>

Nginx Configuration

You'll see below that we're using FastCGI but that's not important. I just left that in to show that we're using the same Django server as well as IP address for both the mobile and full sites. Also note that Nginx doesn't allow you to combine conditionals so we've used a variable called $mobile that we flag to determine whether to redirect.

Finally, here is the Nginx configuration stripped to the essentials.

http { server { listen 1.2.3.4:80; server_name www.domain.com; # Mobile User Agent Check if ($http_user_agent ~* '(blackberry|blazer|danger|ericsson| Google\s+Wireless\s+Transcoder|htc|iemobile|ipaq|iphone|ipod|lg|mobile| mot|moto|motorola|nec\-|netfront|netfront|nokia|opera\s+mini|palm| palmsource|panasonic|philips|pocketpc|samsung|sanyo|sec|sharp|sie\-| smartphone|sony|symbian|t\-mobile|untrusted|up\.browser|up\.link| vodafone\/|wap1\.|wap2\.|webOS|windows\s+ce)') { set $mobile on; } location / { fastcgi_pass unix:/path/to/the/django-server.socket; # ... if ($query_string ~ "full") { add_header Set-Cookie "mobile=off;path=/"; set $mobile off; } if ($http_cookie ~ "mobile=off") { set $mobile off; } if ($query_string ~ "mobile") { set $mobile on; } if ($mobile = on) { rewrite ^(.*)$ http://m.domain.com$ break; } } } server { listen 1.2.3.4:80; server_name m.domain.com; location / { fastcgi_pass unix:/path/to/the/django-server.socket; # ... if ( $query_string ~ "full" ) { rewrite ^(.*)$ http://www.domain.com$ break; } } } }

Mobile Development: Django Setup

When it comes to how Django is handled, you have to make some more choices. For some scenarios, you may need to provide variations in your application's views for mobile. I won't cover that in detail here but there are several reusable apps out there to help if you find you have more advanced requirements. Check out django-mobile or minidetector.

Django Middleware

We found that we could accomplish everything without the need to update any of our existing applications by using a simple middleware for changing the project template directory inspired by this snippet from Nathan Borror.

Put the following into the middleware.py file of a logical application or create a new one if that makes more sense.

from django.conf import settings class MobileMiddleware(object): def process_request(self, request): subdomain = request.META.get('HTTP_HOST', '').split('.') if 'm' in subdomain: settings.TEMPLATE_DIRS = settings.MOBILE_TEMPLATE_DIRS else: settings.TEMPLATE_DIRS = settings.DESKTOP_TEMPLATE_DIRS

Django Settings

Then add it to the middleware classes in your settings.py.

MIDDLEWARE_CLASSES = ( 'django.middleware.doc.XViewMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'yourapplication.middleware.MobileMiddleware', )

Finally, change your template directory settings to something like this:

DESKTOP_TEMPLATE_DIRS = ( '/path/to/your/project/templates', ) MOBILE_TEMPLATE_DIRS = ( '/path/to/your/project/mobile_templates', ) + DESKTOP_TEMPLATE_DIRS TEMPLATE_DIRS = DESKTOP_TEMPLATE_DIRS

This allows us to override any templates we'd like for our mobile version and still fall back to our full site versions when they don't exist. Your mobile_templates folder may consist of only a base_site.html template and for most projects that should be enough to significantly overhaul the layout and design of the entire site.

You're done! Now comes the fun part; trying to make your slick, new, fluid, slimmed down UI render properly in any number of ancient Nokia/RIM/Palm devices with varying CSS/JavaScript support your clients may be using. Good luck out there.