Mobilize your Django site
This is the code for a Django middleware class to allow you to easily mobilize your Django site. It makes use of Wapple.net's Web services to provide device profiling and markup generation.
Using this middleware plugin, you can deliver your site to both mobile and web browsers using the same domain and exactly the same url structure and Python views. The WAPL markup language allows you to render sites to every single mobile device without worrying about the individual devices yourself.
Requirements
- The SUDS Python SOAP client.
- A WAPL dev key. Sign up for one at http://wapl.info
- The Django sessions framework must be enabled. See http://docs.djangoproject.com/en/dev/topics/http/sessions/ for how to install.
How To Use
- Save the code above as 'wapl_middleware.py' in the root of your project.
- Replace 'YOUR-DEV-KEY-HERE' with your WAPL dev key.
- In your project's 'settings'py', add the following to the bottom of your 'MIDDLEWARE_CLASSES' setting:
'myapp.wapl_middleware.WAPLMiddleware',
- For each line in your 'TEMPLATE_DIRS' setting, create a new folder under that folder called 'wapl' e.g. for 'myapp/templates/', you would create the folder under 'myapp/templates/wapl/'.
- For each template used in your application, write a WAPL version and save it in the corresponding 'wapl' directory. See http://wapl.info/docs/chapter/Developing-with-WAPL/ for information about the WAPL markup language.
- Django template inheritance and includes can be used as normal, so I recommend creating a 'base.html' like this one.
<?xml version="1.0" encoding="UTF-8" ?>
<wapl xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://wapl.wapple.net/wapl.xsd">
<head>
{% block wapl_head %}{% endblock %}
</head>
<layout>
{% block wapl_layout %}{% endblock %}
</layout>
</wapl>
- View your site from a mobile device, and you should see a nice mobile version.
How It Works
- When a request is made, the middleware checks to see if a session variable is held telling us if the device is mobile or not.
- If we don't already know, it calls the WAPL web services to check. It then stores this in the session for subsequent requests.
- If the device is a mobile device, it appends 'wapl' to each line in your 'TEMPLATE_DIRS' setting. Your view code will work exactly the same as normal, and the 'wapl' templates will be used whenever a response is rendered.
- When a response is about to be rendered, the middleware checks to see if the device is a mobile one.
- If it is mobile, and the response about to be sent has a status code of 200 (OK), it sends the WAPL markup to the WAPL web service to generate the correct markup for that device.
- Otherwise, it outputs the response unmodified.
Tips
- Don't try to migrate your whole site to mobile - design for mobile and consider the user's goals on a handset.
- If leaving sections out, don't just leave the wapl view out. Include one that says 'This page is not available on mobile'. This will make sure none of your external links are dead on the mobile version.
- For full developer reference, information and schemas, see http://wapl.info.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | from suds.client import Client
from suds import WebFault
from django.conf import settings
from django.http import HttpResponse
import logging
from xml.dom import minidom
class WAPLMiddleware(object):
"""
A Django middleware class that mobilises an existing Django app
with miminal effort.
It integrates with the WAPL markup language provided by Wapple.net,
via SOAP calls.
Please see http://wapl.info for more information.
"""
url = 'http://webservices.wapple.net/wapl.wsdl'
dev_key = 'YOUR-DEV-KEY-HERE'
session_var_name = 'is_mobile'
template_sub_dir = 'wapl'
is_mobile = False
#Set debug_wapl to true to debug your WAPL. Your WAPL will be outputted without being sent to the webservice.
#This is useful if you encounter WAPL parsing errors.
#You can turn this on and use the validator at http://wapl.info to check for errors.
debug_wapl = False
def __init__(self):
##
## Uncomment the below lines to print SOAP messages to the console.
## Useful for debugging SOAP errors.
##
#logging.basicConfig(level=logging.INFO)
#logging.getLogger('suds.client').setLevel(logging.DEBUG)
self.init_client()
def handle_request_error(self, error, request):
"""
Handles any SOAP errors sent back from the SOAP server during the
process_request function.
"""
##
## Your error handling goes here.
##
## This should return an HttpResponse object or
## None to continue processing the request
##
##
raise error
def handle_response_error(self, error, request, response):
"""
Handles any SOAP errors sent back from the SOAP server during the
process_response function.
"""
##
## Your error handling goes here.
##
## This should return an HttpResponse object or
## None to continue processing the request
##
##
raise error
def init_client(self):
"""
Initialises the SOAP client.
"""
self.client = Client(self.url)
def append_td(self, td):
"""
Ammends a template directory setting to the wapl version.
"""
if td[(-1-len(self.template_sub_dir)):] == '%s/' % self.template_sub_dir:
return td
if td[-1] != '/':
td = td + '/'
return td + '%s/' % self.template_sub_dir
def restore_td(self, td):
"""
Restores the template directory setting ready for the next request
"""
if td[(-1-len(self.template_sub_dir)):] == '%s/' % self.template_sub_dir:
return td[:-5]
else:
return td
def build_headers(self,request):
"""
Builds the request headers into the appropriate form to
post to the SOAP call.
"""
headers = self.client.factory.create('deviceHeaders')
for name, val in request.META.items():
item = self.client.factory.create('deviceItem')
item.name = name
item.value = val
headers.deviceItem.append(item)
return headers
def process_request(self,request):
"""
Checks if the device is a mobile device by:
1. Checking if the user has 'is_mobile' in their session.
2. Calling the WAPL web service.
If the device is not mobile, it does nothing, otherwise
it modifies the TEMPLATE_DIRECTORIES setting to look for templates
in a wapl/ subfolder.
"""
if self.session_var_name in request.session:
self.is_mobile = request.session[self.session_var_name] == 'True'
else:
self.init_client()
try:
self.is_mobile = self.client.service.isMobileDevice(self.dev_key,self.build_headers(request)) == '1'
except WebFault, w:
return self.handle_request_error(w, request)
request.session[self.session_var_name] = str(self.is_mobile)
if self.is_mobile:
settings.TEMPLATE_DIRS = tuple([self.append_td(td) for td in settings.TEMPLATE_DIRS])
def process_response(self,request,response):
"""
If the device is mobile, and the response code is OK,
it generates the correct markup for the requesting device by
calling the WAPL web service.
Otherwise, it returns the response untouched.
"""
settings.TEMPLATE_DIRS = tuple([self.restore_td(td) for td in settings.TEMPLATE_DIRS])
if response.status_code != 200 or self.debug_wapl or "text/html" not in response['Content-Type']:
return response
if self.is_mobile:
self.is_mobile = False
self.init_client()
wapl = response.content
try:
wapl_response = self.client.service.getMarkupFromWapl(self.dev_key,wapl,self.build_headers(request))
except WebFault, w:
return self.handle_response_error(w,request,response)
doc = minidom.parseString(wapl_response)
markup = doc.getElementsByTagName('markup')[0].childNodes[1].data
return HttpResponse(markup)
else:
return response
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.