12
2012
Serving mobile version of your Django app when using Varnish
You are building a Django news app, deadline is closing and you need to satisfy the X percentage of your users now accesing the site through their smartphones without getting a low Varnish cache hit rate.
In the ideal world a fully responsive design might be a solution – catering for all devices and looking good across all screen sizes.
But in my world we still have a mobile version of our website (served by our CMS), the ad systems are completely different on the mobile and full versions, and so are the video players, page headers, footers etc.
«Adaptive design light»
My approach is «adaptive design light». The aim is to make the content of the news app itself as adaptive or responsive as possible to save time and be able to update often. That means using media queries on the main app content.
The headers, footers and ad system is included via ESI in the Varnish boxes caching up my Django content. But that also means I need different ESI-tags for mobile and full version. In the Django world I need separate base.html templates with ESI-tags in.
Meet django-mobile
The original django-mobile app adds device detection to your Django project and lets you create separate templates for mobile devices (in template subfolder mobile, i.e. /mobile/base.html). It falls back to the original template if no mobile template is found.
So far so good, using django-mobile I can serve up different base templates for my mobile and full versions of the site.
Device detection
In our CMS and mobile version of the main site, there is (or has been) a full device detection using wurfl and adaption of serverside code to different devices ranging from smallest screens/models to iPhone and Android.
In my world that is to much server side code, and in a rapid changing news app world it would take to much time and code to maintain. And caching gets extremely difficult, so I only care about mobile or not.
But since I need to cache to versions of every page (mobile or not) the device detection has to happen before the request hits the Django app servers.
You could do that in Varnish (there is a good writeup here), but we have a load balancer/gateway that can do that.
Caching different versions
What troubled me the most was how to cache different versions of the site in Varnish and still be able to invalidate (purge) single pages and by that purge both the mobile and full version.
The solution I found was this (there are possibly a lot more nifty solutions, but I am a journalist and not a http header specialist)..
- Our gateway/load balancer checks if the device is some kind of mobile device. If so, it sets an http header value of
X-PLATTFORM="mobile"
- Varnish detects this header value, and using the VCL we tell Varnish to «vary» on that header. That means it will cache different versions of the page depending on the value of the X-PLATTFORM header.
sub vcl_fetch { .... set beresp.http.Vary = "X-PLATTFORM"; .... } - By default the django-mobile app detects device and sets a variable («flavour») that is used to serve the right templates and/or content for your device. Since I don’t need that, but instead need it to take into account the X-Plattform header, I wrote a small middleware (PlattformHeaderDetectionMiddleware) to do that in my fork of django-mobile. Add it to your middlewares:
MIDDLEWARE_CLASSES = ( .... 'django_mobile.middleware.PlattformHeaderDetectionMiddleware', 'django_mobile.middleware.SetFlavourMiddleware', .... )The SetFlavourMiddleware lets you override/debug using flavour=mobile or flavour=full url parameter.
- You can now use the functionality of django-mobile to serve up different content/templates based on the X-Plattform header.
Notes on template caching
If you use template caching in Django (you should) you would see that Django only caches one version of your templates and disregarding mobile/full version. To avoid that, use the CachedLoader template loader of django-mobile like this in your settings.py:
#cache the templates
TEMPLATE_LOADERS = (
('django_mobile.loader.CachedLoader', (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
'django.template.loaders.eggs.Loader',
)),
)
Puring/invalidating content for all platforms
When purging your articles/pages you want it to happen for all cached versions of the page regardless of device.
That is simple if you use django-varnish as it purges via the management port – that means purging all versions regardless of Vary etc.
Useful links
- Fork of django-mobile that includes http header detection and caching of templates: https://github.com/anderser/django-mobile
- Varnish integration for Django to simplify purging: https://github.com/justquick/django-varnish or my fork which also has purging of old urls stored in Django redirect: https://github.com/anderser/django-varnish
- More on Varnish VCLs Vary: https://www.varnish-cache.org/docs/trunk/tutorial/vary.html
Leave a comment
Prosjekter
- Det hemmelige brorskap – frimurerne
- Her ble det flest nye millionærer
- Her forsvant Eldremilliarden
- Her ryker førerkortene -
- Nasjonale prøver 2008 – resultatene
- Norskekysten uten politibåter
- Politisk panel – raske meninger
- Sovner ved roret
- Statsbudsjettet for dummies Trekart over budsjettfordelingen
- TV 2 sjekker kjølediskene
- Velgerguiden 2009 Stortingskandidatene samlet
- Velgerguiden 2011 59.000 kandidater til kommunevalget 2011
Kategorier
- English (1)
- Guider (1)
- Nettskraping (1)
- Norwegian (1)
An article by Anders




