基于用户代理改变Django模板

我做了一个Django网站,但是我已经喝了Koolaid,我想要制作一个iPhone版本。 经过深思熟虑后,我提出了两个select:

  1. 做一个完整的其他网站,如i.xxxx.com。 使用Django的网站框架将其绑定到相同的数据库中。
  2. 找一些读取用户代理的中间件,并dynamic改变模板目录。

但是,我真的更喜欢选项#2。 我有一些保留,主要是因为Django的文档不能dynamic改变设置 。 我find了一个可以做我想要的片段 。 我的主要问题是让它尽可能无缝,我希望它是自动的,对用户是透明的。

有没有其他人遇到同样的问题? 有人会关心分享他们如何解决使Django网站的IPhone版本?

更新

我与中间件的组合,并调整模板调用。

对于中间件,我使用minidetector 。 我喜欢它,因为它检测到大量的移动用户代理。 我所要做的就是在我的意见中检查request.mobile。

对于模板调用调整:

def check_mobile(request, template_name): if request.mobile: return 'mobile-%s'%template_name return template_name 

我用这个任何观点,我知道我有两个版本。

去做:

  • 弄清楚如何在render_to_response的扩展版本中访问request.mobile ,所以我不必使用check_mobile('template_name.html')
  • 如果不存在移动版本,则使用以前的自动回退到常规模板。

而不是dynamic地改变模板目录,你可以修改请求并添加一个值,让你的视图知道用户是否在iphone上。 然后包装render_to_response(或者你用来创buildHttpResponse对象的任何东西)来获取模板的iphone版本,而不是标准的html版本,如果他们使用的是iphone。

检测中间件中的用户代理,切换url绑定,获利!

怎么样? Django请求对象有一个.urlconf属性,可以由中间件来设置。

从Django文档:

Django确定要使用的根URLconf模块。 通常,这是ROOT_URLCONF设置的值,但是如果传入的HttpRequest对象具有名为urlconf(由中间件请求处理设置)的属性,则将使用其值替代ROOT_URLCONF设置。

  1. 在你的proj / middlware.py中,写一个检查http_user_agentstring的类:

     import re MOBILE_AGENT_RE=re.compile(r".*(iphone|mobile|androidtouch)",re.IGNORECASE) class MobileMiddleware(object): def process_request(self,request): if MOBILE_AGENT_RE.match(request.META['HTTP_USER_AGENT']): request.urlconf="yourproj.mobile_urls" 
  2. 不要忘记在settings.py中添加这个MIDDLEWARE_CLASSES:

     MIDDLEWARE_CLASSES= [... 'yourproj.middleware.MobileMiddleware', ...] 
  3. 创build一个移动urlconf,yourproj / mobile_urls.py:

     urlpatterns=patterns('',('r'/?$', 'mobile.index'), ...) 

本文可能是有用的: 在15分钟内在Django中构build移动和桌面友好的应用程序

我正在开发一个django移动扩展程序djangobile: http : //code.google.com/p/djangobile/

你应该看看django-mobileadmin源代码,它解决了这个问题。

其他方法是创build自己的模板加载器,加载特定于用户代理的模板。 这是非常通用的技术,可以用来根据其他因素dynamic地确定需要加载的模板,比如所需的语言(与现有的Django i18n机器的良好配套)。

Django Book有一个关于这个主题的部分 。

有一篇不错的文章解释了如何通过不同的模板呈现相同的数据http://www.postneo.com/2006/07/26/acknowledging-the-mobile-web-with-django

你仍然需要自动将用户redirect到移动站点,但是这可以通过几种方法完成(你的check_mobile技巧也可以)

在parsing某些中间件中的UA之后,如何将用户redirect到i.xxx.com? 我非常怀疑移动用户关心url的样子,他们仍然可以使用主要url访问您的网站。

最好的scheme:使用minidetector添加额外的信息到请求,然后使用Django的内置的请求上下文将它传递给你的模板

 from django.shortcuts import render_to_response from django.template import RequestContext def my_view_on_mobile_and_desktop(request) ..... render_to_response('regular_template.html', {'my vars to template':vars}, context_instance=RequestContext(request)) 

那么在你的模板中你可以引入如下的东西:

 <html> <head> {% block head %} <title>blah</title> {% if request.mobile %} <link rel="stylesheet" href="{{ MEDIA_URL }}/styles/base-mobile.css"> {% else %} <link rel="stylesheet" href="{{ MEDIA_URL }}/styles/base-desktop.css"> {% endif %} </head> <body> <div id="navigation"> {% include "_navigation.html" %} </div> {% if not request.mobile %} <div id="sidebar"> <p> sidebar content not fit for mobile </p> </div> {% endif %> <div id="content"> <article> {% if not request.mobile %} <aside> <p> aside content </p> </aside> {% endif %} <p> article content </p> </aricle> </div> </body> </html> 

一个简单的解决scheme是创build一个django.shortcuts.render的包装。 我把它放在应用程序的根目录中的utils库中。 包装器通过在“移动”或“桌面”文件夹中自动呈现模板来工作。

utils.shortcuts

 from django.shortcuts import render from user_agents import parse def my_render(request, *args, **kwargs): """ An extension of django.shortcuts.render. Appends 'mobile/' or 'desktop/' to a given template location to render the appropriate template for mobile or desktop depends on user_agents python library https://github.com/selwin/python-user-agents """ template_location = args[0] args_list = list(args) ua_string = request.META['HTTP_USER_AGENT'] user_agent = parse(ua_string) if user_agent.is_mobile: args_list[0] = 'mobile/' + template_location args = tuple(args_list) return render(request, *args, **kwargs) else: args_list[0] = 'desktop/' + template_location args = tuple(args_list) return render(request, *args, **kwargs) 

view

 from utils.shortcuts import my_render def home(request): return my_render(request, 'home.html')