flask多蓝图模板目录冲突解决

一、环境

Flask==0.10.1

Werkzeug==0.10.4

Jinja2==2.8

二、问题

1、蓝图架构

--app

|-user

|-static

|-templates

|-index.html

|-views.py

|-__init_.py

|-box

|-static

|-templates

|-index.html

|-views.py

|-__init_.py

|-__init__.py

2、问题重现

user和box是两个蓝图,全部注册在app项目中

如果在user的views中这样【render_template(‘index.html‘)】渲染index.html,可能会访问到别的蓝图下的同名模板文件。

三、分析

1、app创建时会从Flask注册函数中读取template_folder,如果没有设置,默认是app/templates,作为全局jinja_loader

2、render_template函数会首先访问app的全局jinja_loader,从中读取模板路径。

3、访问不到就会循环访问所有注册蓝图的jinja_loader。由于循环访问的是所有蓝图的无序键值字典, 所以恰巧碰到其中一个蓝图下有同名模板文件,便会渲染这个模板文件。

4、附上关键代码(/usr/lib/python2.6/site-packages/flask/templating.py)

    def get_source(self, environment, template):
        for loader, local_name in self._iter_loaders(template):
            try:
                return loader.get_source(environment, local_name)
            except TemplateNotFound:
                pass
 
        raise TemplateNotFound(template)
 
    def _iter_loaders(self, template):
        loader = self.app.jinja_loader
        if loader is not None:
            yield loader, template
 
        # old style module based loaders in case we are dealing with a
        # blueprint that is an old style module
        try:
            module, local_name = posixpath.normpath(template).split(‘/‘, 1)
            blueprint = self.app.blueprints[module]
            if blueprint_is_module(blueprint):
                loader = blueprint.jinja_loader
                if loader is not None:
                    yield loader, local_name
        except (ValueError, KeyError):
            pass
        for blueprint in itervalues(self.app.blueprints):
            if blueprint_is_module(blueprint):
                continue
            loader = blueprint.jinja_loader
            if loader is not None:
                yield loader, template

四、解决办法

1、官方给出的解决办法(妥协)

将所有模板文件放在一起,按蓝图名字划分子目录。也就是全部都放在app的全局jinja_loader目录。访问的时候,使用render_template(‘blueprint_name/template_file.html‘)这种方式。参见:http://flask.pocoo.org/docs/0.10/blueprints/#templates

2、其他友人的解决办法

在创建app时修改全局jinja_loader,改为ChoiceLoader类型,使每个注册的蓝图loader都作为一个字典元素插入到ChoiceLoader中的PrefixLoader中,这样在访问时就可以在PrefixLoader中根据传进的蓝图名查找到当前loader路径。

作者称这样的好处不用修改项目架构。不过这样也会有个问题:使用渲染函数时需要修改模板字符串,因为是PrefixLoader,需要添加delimiter标示,比如访问user下的index.html要这样render_template(‘user.index.html‘);参见:http://fewstreet.com/2015/01/16/flask-blueprint-templates.html

3、github上的commit

这种方法修改了render_template函数,在渲染模板时判断是否是蓝图以及是否存在蓝图loader。如果存在优先使用蓝图自身的loader。这种方法比较干脆直接,参见:https://github.com/mitsuhiko/flask/pull/1537/files

4、我的解决方式

参照了github解决方法的思路,我在注册app时通过before_request修改全局jinja_loader,在收到请求时临时把当前蓝图的loder路径添加到全局jinja_loader的searchpath列表中,这样做的目的:①避免修改项目结构,②避免修改render_template参数,③避免修改框架代码,不方便迁移部署。

五、我的代码(app/__init__.py)

def create_app(env=‘development‘):    
    """此处略去若干行"""        
    @app.before_request    
    def before_request():        
        if request.blueprint is not None:            
            bp = app.blueprints[request.blueprint]            
            if bp.jinja_loader is not None:                
                newsearchpath = bp.jinja_loader.searchpath + app.jinja_loader.searchpath
                app.jinja_loader.searchpath = newsearchpath
时间: 2024-08-06 09:53:37

flask多蓝图模板目录冲突解决的相关文章

Django和Angular.js模板标签冲突的解决方式

参考文章:http://yanhua365.lofter.com/post/b417f_1f0361 http://stackoverflow.com/questions/8302928/angularjs-with-django-conflicting-template-tags http://blog.boxelderweb.com/2012/11/16/providing-django-template-variables-as-constants-to-angularjs/ 说在前面的话

svn conflict 冲突解决

转自:http://www.gezila.com/tutorials/17290.html 目录: 1. 同一处修改文件冲突 1.1. 解决方式一 1.2. 解决方式二 1.3. 解决总结 2. 手动解决冲突 2.1. 冲突背景1 2.2. 冲突背景2 2.3. 冲突解决 1. 同一处修改文件冲突 开发人员都知道代码管理工具是开发中一个必不可少的工具,这里也不废话详细介绍了.不管你个人喜欢git还是svn还是其他,但还有一大部分公司在使用svn做代码管理工具.这里详细介绍下SVN提交文件时冲突问

Git merge 冲突解决简明教程

目录 1.????概述????1 2.????从git difftool & mergetool 工具开始 – Beyond Compare????1 2.1.????下载安装Beyond Compare????1 2.2.????创建启动Beyond Compare脚本????1 2.2.1.????创建git-difftool-bcomp-wrapper.sh????2 2.2.2.????创建git-mergetool-bcomp-wrapper.sh????2 2.3.????设置环境变

[转]SVN版本冲突解决详解

原文地址:http://blog.csdn.net/windone0109/article/details/4857044 版本冲突原因: 假设A.B两个用户都在版本号为100的时候,更新了kingtuns.txt这个文件,A用户在修改完成之后提交kingtuns.txt到服务器,这个时候提交成功,这个时候kingtuns.txt文件的版本号已经变成101了.同时B用户在版本号为100的kingtuns.txt文件上作修改,修改完成之后提交到服务器时,由于不是在当前最新的101版本上作的修改,所

Git下的冲突解决

冲突的产生 很多命令都可能出现冲突,但从根本上来讲,都是merge 和 patch(应用补丁)时产生冲突. 而rebase就是重新设置基准,然后应用补丁的过程,所以也会冲突. git pull会自动merge,repo sync会自动rebase,所以git pull和repo sync也会产生冲突.当然git rebase就更不用说了. 冲突的类型 逻辑冲突 git自动处理(合并/应用补丁)成功,但是逻辑上是有问题的. 比如另外一个人修改了文件名,但我还使用老的文件名,这种情况下自动处理是能成

多jdk环境下安装多个tomcat冲突解决配置方法

                                                 文章转载自:[169IT-最新最全的IT资讯] 参考方案一: 一个服务器两个jdk,一个是jdk1.4,一个是jdk1.6. 同样tomcat版本是,tomcat5.0和tomcat6.0.都安装在一个服务器上. tomcat5.0匹配jdk1.4, tomcat6.0匹配jdk1.6, 1.首先指定tomcat匹配的jdk tomcat/bin目录下 catalina.bat setclasspa

svn冲突问题详解 SVN版本冲突解决详解

(摘自西西软件园,原文链接http://www.cr173.com/html/46224_1.html) 解决版本冲突的命令.在冲突解决之后,需要使用svnresolved来告诉subversion冲突解决,这样才能提交更新.冲突发生时,subversion会在WorkCopy中保存所有的目标文件版本(上次更新版本.当前获取的版本,即别人提交的版本.自己更新的版本.目标文件. 开发人员都知道代码管理工具是开发中一个必不可少的工具,这里也不废话详细介绍了.不管你个人喜欢git还是svn还是其他,但

svn版本分支及冲突解决笔记

转载:http://blog.csdn.net/xuguiyi100/article/details/51966557 分支合并主干示例 1.主干工程右键选择merge合并下一步 2.选中merge two different trees下一步 3.from主干版本路径,版本号选择分支分出去的版本号 to合并的分支目录,版本号一般最新版本 下一步 4.选择属性,一般直接下一步即可 5.下一步完成.若无冲突直接主干提交代码即可. 若存在冲突解决办法,个人建议使用最后一种解决冲突 Mark as c

SVN版本冲突解决详解 - snwrking的专栏 - 博客频道 - CSDN.NET

版本冲突原因: 假设A.B两个用户都在版本号为100的时候,更新了kingtuns.txt这个文件,A用户在修改完成之后提交kingtuns.txt到服务器,这个时候提交成功,这个时候kingtuns.txt文件的版本号已经变成101了.同时B用户在版本号为100的kingtuns.txt文件上作修改,修改完成之后提交到服务器时,由于不是在当前最新的101版本上作的修改,所以导致提交失败. 版本冲突现象: 冲突发生时,subversion会在当前工作目录中保存所有的目标文件版本[上次更新版本.当