lunes, 24 de octubre de 2011

Diferentes páxinas para dispositivos móviles e fixos

Problema

Temos páxinas que se leen con dificultade en dispositivos móviles, como iPhone e Android. Buscando por ahí adiante atopéi varios enfoques, e o máis extendido é analizar a petición do cliente (HTTP_USER_AGENT sobre todo) para ver si pertence a un dispositivo móvil. Unha vez determinado, aplicar a solución requerida

A base

Partín da base de Django mobile utils, que implementa unha solución robusta. Cando chega a petición (request), antes de chegar ó views.py pasa por un middleware que intenta averiguar si o USER_AGENT é móbil. A función está no __init__.py, e garda o request nunha variable local. Aquí é donde me falla, xa que non consigo recuperar as variables locais. Despóis de pasar polo middleware, o request orixinal está marcado como .is_mobile = True. Hai un código para cargar os "templates" alternativos, dentro de loaders.py; este loader mira dentro da variable local de request si ten o valor .is_mobile == True, porque non se lle pode pasar como parámetro o propio request. Así que si falla o request local, falla todo.
Por sorte, o autor tamén incluiu un context_processor, que simplemente se encarga de pasarlle un diccionario de variables ós templates. Por exemplo, si activamos o context_procesor de auth, en tódolos templates teremos dispoñibles un número de variables como user.

A solución

Utilizando o código anterior, podemos simplificalo para utilizar só o __init__.py e o context_processor.py. Os context_processors deben manterse simples según o manual oficial, así que si podemos pasar só unha variable, mellor que dúas. Dende o context_processor.py orixinal:
def mobile_browser(request):
    dict = {'mobile_browser': False}
    if hasattr(request, 'is_mobile'):
        dict['mobile_browser'] = request.is_mobile
    return dict
Podemos pasar a outro context máis simple aínda, como:
def mobile_browser(request):
    dict = {'mobile_browser': False}
    if our_server.django_mobile_utils.is_mobile(request):
        dict['mobile_browser'] = True
    return dict
Vemos que o autor orixinal sigue tirando de request acumulado en local, pero nós imos testear directamente o request. Modificamos tamén o código do __init__.py. Das varias liñas de tipo:
request.mobile = True
return request
Cambiamos a:
return True
E a última liña que pon return request cambiámola a return False. Ou adornamos con variables, si nos gusta máis.
Si estamos pola simplificación extrema, todas as globáis deste archivo pódense eliminar, así como a configuración no settings.py, no que chega con engadir:
TEMPLATE_CONTEXT_PROCESSORS = (
    "our_server.django_mobile_utils.context_processors.mobile_browser",
    ...

Aplicación

Agora temos no directorio django_mobile_utils os arquivos __init__.py, context_processor.py e un directorio data/mobile_agents.txt, e o settings.py modificado como corresponde. ¿Cómo ó usamos? Simplemente, nos templates utilizamos a variable booleana {{mobile_browser}} como condicional, por exemplo para cargar unha folla de estilo diferente:
{% if mobile_browser %}
  <link href="/media/css/mobile_style.css" rel="stylesheet" type="text/css" />
{% else %}
  <link href="/media/css/style.css" rel="stylesheet" type="text/css" />
{% endif %}

No hay comentarios: