Python 基于用户代理更改Django模板

Python 基于用户代理更改Django模板,python,django,django-templates,mobile-website,django-middleware,Python,Django,Django Templates,Mobile Website,Django Middleware,我已经制作了一个Django网站,但我已经喝了Kooled,我想制作一个IPhone版本。经过深思熟虑,我想出了两个选择: 创建一个完整的其他网站,如i.xxxx.com。使用Django的sites框架将其绑定到同一个数据库中 找一段时间的中间件来读取用户代理,并动态更改模板目录 然而,我真的更喜欢选项2;我有一些保留,主要是因为Django文档。我找到了一个可以做我想做的事的。我的主要问题是让它尽可能无缝,我希望它是自动和透明的用户 还有其他人遇到过同样的问题吗?有没有人愿意分享一下他们是如

我已经制作了一个Django网站,但我已经喝了Kooled,我想制作一个IPhone版本。经过深思熟虑,我想出了两个选择:

  • 创建一个完整的其他网站,如i.xxxx.com。使用Django的sites框架将其绑定到同一个数据库中
  • 找一段时间的中间件来读取用户代理,并动态更改模板目录
  • 然而,我真的更喜欢选项2;我有一些保留,主要是因为Django文档。我找到了一个可以做我想做的事的。我的主要问题是让它尽可能无缝,我希望它是自动和透明的用户

    还有其他人遇到过同样的问题吗?有没有人愿意分享一下他们是如何解决制作IPhone版Django网站的问题的

    更新

    我使用了中间件和调整模板调用的组合

    对于中间件,我使用了。我喜欢它,因为它能检测到大量的移动用户代理。我所要做的就是在我的视图中检查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')
    • 如果不存在移动版本,则使用以前的自动回退到常规模板

    您可以修改请求并添加一个值,让您的视图知道用户是否在iphone上,而不是动态更改模板目录。然后包装render_to_response(或用于创建HttpResponse对象的任何内容),以获取模板的iphone版本,而不是使用iphone的标准html版本

    在某些中间件中解析用户的UA后,如何将用户重定向到i.xxx.com?我非常怀疑移动用户是否关心url的外观,但他们仍然可以使用主url访问您的网站。

    您应该看看源代码,它正好解决了这个问题。

    另一种方法是创建您自己的模板加载器,加载特定于用户代理的模板。这是一种非常通用的技术,可用于根据其他因素动态确定必须加载的模板,如请求的语言(与现有的Django i18n机制很好的搭配)


    Django的书有一个。

    我正在开发djangobile,一个Django移动扩展:

    有一篇很好的文章,解释了如何通过不同的模板呈现相同的数据


    但是,您仍然需要自动将用户重定向到移动站点,这可以使用多种方法完成(您的check_mobile技巧也会起作用)

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

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

    来自django文档:

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

  • 在yourproj/middlware.py中,编写一个类来检查http\u user\u代理字符串:

    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"
    
  • 别忘了将其添加到settings.py中的中间件类中:

    MIDDLEWARE_CLASSES= [...
        'yourproj.middleware.MobileMiddleware',
    ...]
    
  • 创建移动urlconf,yourproj/mobile_url.py:

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

  • 最好的方案是:使用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>
    
    
    {%block head%}
    废话
    {%if request.mobile%}
    {%else%}
    {%endif%}
    {%include“_navigation.html”%}
    {%if not request.mobile%}
    侧边栏内容不适合移动设备

    {%endif%> {%if not request.mobile%} 旁白内容

    {%endif%} 文章内容


    一个简单的解决方案是围绕
    django.shortcuts.render
    创建一个包装器。我将我的包装器放在我的应用程序根目录下的
    utils
    库中。包装器通过在“mobile”或“desktop”文件夹中自动呈现模板来工作

    utils.shortcuts
    中:

    视图中


    可能是最好的方法…我只是不想在视图中添加额外的代码。谢谢你的回答!我要做的是编写自己的render\u to\u响应包装器,并将其放入项目范围的实用程序库中。然后只需导入它而不是render\u to\u响应(如我的render\u响应)。您的视图中有相同数量的代码,只需更改视图中的导入和func调用即可。@imjoevasquez这是事后的做法,但您始终可以从my_site\u wide\u stuff执行类似于
    的操作。utils将my_render\u to_response导入为render\u to_response
    -因为
    render\u to_response
    只是一种快捷方式nyways。虽然查找/替换可能是一种方法;)如果我试图根据移动设备或桌面在DOM的不同位置呈现模板,您会推荐相同的方法吗?您也可以这样做/需要这样做,以拥有一个特殊的IE6版本的模板。我考虑使用1个模板,如果用户代理s IE6。我喜欢你这样做:)你会说我有太多的Pinata吗?请注意,不幸的是,minidetector似乎与Python 3不兼容。请参阅以获取替代方案。这有什么帮助?你仍然有网站的模板名称和布局。或者你创建了一整套新的逻辑,或者问题仍然存在。
    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)
    
    from utils.shortcuts import my_render
    
    def home(request):    return my_render(request, 'home.html')