django中基于用户代理的移动模板确保线程安全

时间:2016-03-08 09:39:15

标签: django django-templates thread-safety mobile-website django-middleware

我正在开发我的网站的移动版本,因此考虑使用用户代理作为为移动和网络版本提供不同模板的标准。 我成功地从nginx读取了用户代理信息,并将其作为标题传递给gunicorn服务器。

然后我创建了一个中间件,它读取此标头并更改设置文件中的模板目录。这似乎最初起作用但后来我意识到存在竞争条件,因为这种方法不是线程安全的。 (我应该事先想到它)。

所以我开始考虑其他选择。一种解决方案是覆盖django的render方法以包括基于请求头的“dirs”参数。但后来我发现“dirs”参数已被弃用。以下是参考链接https://docs.djangoproject.com/en/1.9/_modules/django/shortcuts/#render 所以即使这样也行不通。

另一种解决方案是为移动设备和网络设置不同的模板名称并相应地加载它们。但是我不想这样做,并希望保持模板目录结构与Web和移动设备完全相同。

必须有一种方法可以覆盖模板目录。如果在移动模板目录中缺少模板的Web版本,这将给我一个优势。

任何有关如何实现这一目标的建议都会有所帮助。

这就是我的模板的组织方式。

App1
   templates
       App1
           index.html
           catalog.html
App2
   templates
       App2
           about.html

在项目目录(不是app文件夹的一部分)中,有一个移动模板文件夹,其结构如下

mobile-templates
    App1
        index.html
    App2
        about.html

由于 阿努拉格

2 个答案:

答案 0 :(得分:1)

以下是我组织模板的方式:

  1. templates目录 - mobiledesktop内设置两个目录。
  2. 将移动模板保存在mobile目录中的desktop目录和桌面模板中。
  3. 这样您就不必重命名模板了。

    以下是我如何呈现它们:

    1. 在中间件中读取用户代理。
    2. 在名为request的{​​{1}}上设置一个属性,其值为template_prefixmobile,具体取决于用户代理。例如:

      desktop
    3. 在您的视图中,请在模板名称前使用def process_request(self, request): # read user agent and determine if # request is from mobile or desktop # ... if mobile_user_agent: request.template_prefix = 'mobile' else: request.template_prefix = 'desktop' 。例如:

      request.template_prefix
    4. 这将根据值def home(request): ... template = request.template_prefix + '/home.html' return render(request, template) 属性呈现mobiledesktop dirs中的模板。

      更新(根据问题编辑):

      看看你的模板是如何组织的,我会这样做:

      1. 中间件:

        仅为移动请求设置template_prefix

        template_prefix
      2. 查看:

        使用def process_request(self, request): if mobile_user_agent: request.template_prefix = 'mobile-templates' else: request.template_prefix = '' # set an empty string ;抓住os.path.join例外。

        TemplateDoesNotExist
      3. 我测试了这个并且它有效。但是在每个视图中编写import os.path from django.template.loader import get_template from django.template.base import TemplateDoesNotExist def index(request): try: template = os.path.join(request.template_prefix, 'App1/index.html') get_template(template) except TemplateDoesNotExist: template = 'App1/index.html' return render(request, template) 块似乎都是多余的。如果我想出一个更好的解决方案,我会更新。

答案 1 :(得分:0)

现在似乎不可能开箱即用。如果你真的想要遵循这种架构,你必须编写自己的自定义加载器,并找出一种方法来传递请求/指示器,让它知道它的移动请求。

编写加载器并不太难(只需查看Django文件系统加载器,如果请求来自移动设备,请遍历所有templates_dirs并为其添加适当的后缀,以便您也包含移动目录)。

然而,我认为最大的挑战是能够将动态参数传递给它(表明这是一个移动请求)。您可以将此参数存储在会话中,或者在将模板名称传递给自定义渲染器之前修改模板名称(渲染器将删除此指示器部分并获取模板)。