使用 Blueprint 要注意 render_template 函数
此文章主要是为了记录在使用 Flask 的过程中遇到的问题。本章主要讨论 render_template 函数的问题。
使用 Flask 的同学都应该知道,项目中的 url 和视图函数是在字典里一一对应着的,再详细一点,就是 url 对应着 endpoint,视图函数也对应着 endpoint,并且 endpoint 在字典里是唯一存在的。
而对于不同 Blueprint 里的 url,是依靠所注册的蓝图以及不同的前缀来进行区分。但是在视图函数中所调用的 render_template 函数可得不到 endpoint 的支持,如果你使用的不同目录下的一样命名的模板文件,那么就会出现问题了。
先摆事实、再讲道理。
明了问题所在
实例项目的目录结构如下:
app
├── admin
│ ├── errors.py
│ ├── forms.py
│ ├── __init__.py
│ ├── static
│ │ ├── css
│ ├── templates
│ │ ├── index.html
│ ├── views.py
├── __init__.py
├── main
│ ├── errors.py
│ ├── forms.py
│ ├── __init__.py
│ ├── templates
│ │ └── ousi
│ │ ├── index.html
│ │ ├── static
│ │ │ ├── css
│ ├── views.py
├── models.py
该项目中注册两个 Blueprint,即 admin 是所谓的后台管理蓝图,main 是所谓的前台展示蓝图。
蓝图 admin 的 __init__.py 内容如下:
# -*- coding:utf-8 -*-
__author__ = '东方鹗'
from flask import Blueprint
admin = Blueprint('admin', __name__, template_folder="templates", static_folder='static')
# 在末尾导入相关模块,是为了避免循环导入依赖,因为在下面的模块中还要导入蓝本main
from . import views, errors
蓝图 main 的 __init__.py 内容如下:
# -*- coding:utf-8 -*-
__author__ = '东方鹗'
from flask import Blueprint
main = Blueprint('main', __name__, template_folder="templates/ousi",
static_folder='templates/ousi/static')
# 在末尾导入相关模块,是为了避免循环导入依赖,因为在下面的模块中还要导入蓝本main
from . import views, errors
在定义两个蓝图的时候,也对本蓝图所对应的模板文件夹和静态文件夹进行了定义,此文主要关注模板文件夹。
那么,现在就说说出现了什么问题。
在各自蓝图的视图函数中都对主页 '/' 或叫做 'index' 进行了定义。
其中,蓝图 admin 的视图函数定义如下:
@admin.route('/', methods=['GET', 'POST'])
@login_required
def index():
return render_template('index.html')
请记住最后的代码,即 render_template('index.html'),此处调用的模板名叫做 index.html。
蓝图 admin 的视图函数定义如下:
@main.route('/', methods=['GET', 'POST'])
def index():
return render_template('index.html')
请记住最后的代码,即 render_template('index.html'),此处调用的模板名叫做 index.html。
到此,你发现了什么,你发现了什么,我估计你已经看出来两个视图函数的最后一行代码是一样的,说得再精确点,调用的模板名是一样的。但是此处我们要保持清醒,虽然模板名称一样,但是所在目录是不一样的,它们所处的位置是各自所在的蓝图所定义的模板文件夹里。
说了这么多,到底怎么了呢。
这时,如果你测试一下你的程序的话,你会发现两个蓝图所显示的内容是一样的,不管你相信不相信自己的眼睛,它就是一样的界面,而且绝对一样,因为 render_template('index.html') 调用的是同一个模板,它可不会区分蓝图。
那么,到底调用的是那个蓝图下的模板呢??继续往下看。
这时你打开 app/__init__.py,内容如下:
def create_app(config_name):
""" 使用工厂函数初始化程序实例"""
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app=app)
# mail.init_app(app=app)
moment.init_app(app=app)
db.init_app(app=app)
md.init_app(app=app)
login_manager.init_app(app=app)
# 注册蓝本 main
from .main import main as main_blueprint
app.register_blueprint(main_blueprint, url_prefix='/main')
# 注册蓝本 admin
from .admin import admin as admin_blueprint
app.register_blueprint(admin_blueprint, url_prefix='/admin')
# 注册蓝本 main
#from .main import main as main_blueprint
#app.register_blueprint(main_blueprint, url_prefix='/dynamic')
return app
到底调用的是那个蓝图下的模板呢??
这个,我可以明确告诉你,main 和 admin 两个蓝图,哪个在 app/__init__.py 中先注册,就调用那个蓝图的模板,也就是说哪个蓝图注册时所用的代码写得靠上,就调用那个蓝图的模板。
这到底是为什么呢?为什么呢?这是 flask 项目的一个小 bug。写项目的时候,要注意此坑,render_template() 函数里所调用的模板一定要保证命名在整个项目中的唯一性。
号外,号外
今天又发现了一个坑,就是 jinja2 内部的模板调用,比如 include 某某模板的时候,这个被调用的模板名称也需要,而且强烈需要保证在整个项目,记住是整个项目中,其命名要具有唯一性。
使用 Blueprint 要注意 render_template 函数的更多相关文章
- 实验4、Flask基于Blueprint & Bootstrap布局的应用服务
1. 实验内容 模块化工程内容能够更好的与项目组内成员合作,Flask Blueprint提供了重要的模块化功能,使得开发过程更加清晰便利.此外,Flask也支持Bootstrap的使用. 2. 实验 ...
- render_template 网页模板
模板简单介绍: 视图函数:视图函数就是装饰器所装饰的方法,视图函数的主要作用是生成请求的响应,这是最简单的请求.实际上,视图函数有两个作用:处理业务逻辑和返回响应内容.在大型应用中,把业务逻辑和表现内 ...
- Flask从入门到精通之在视图函数中处理表单
在新版hello.py 中,视图函数index() 不仅要渲染表单,还要接收表单中的数据.更新后的index() 视图函数如下: @app.route('/') def index(): name = ...
- flask中Flask()和Blueprint() flask中的g、add_url_rule、send_from_directory、static_url_path、static_folder的用法
1.Blueprint()在蓝本注册函数register_blueprint()中,第一个参数为所注册的蓝本名称.当我们在应用对象上注册一个蓝图时,需要指定一个url_prefix关键字 参数(这个参 ...
- Flask框架函数
title: flask学习笔记 subtitle: 1. flask框架函数 date: 2018-12-14 10:17:28 --- Flask学习 学习Miguel Grinberg的2017 ...
- 用 Flask 来写个轻博客 (11) — M(V)C_创建视图函数
目录 目录 前文列表 视图函数 在 viewspy 文件中定义视图函数 定义右侧边栏的视图函数 为每一张数据表定义视图函数 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask ...
- Inside Flask - app.py - 2
Inside Flask - app.py - 2 Flask 初始化参数 Flass 类是 Flask 框架的核心,一个 flask 对象处理视图函数注册.URL规则.模板配置.参数设置等等. 一般 ...
- Flask蓝图
它的作用就是将 功能 与 主服务 分开怎么理解呢? 比如说,你有一个客户管理系统,最开始的时候,只有一个查看客户列表的功能,后来你又加入了一个添加客户的功能(add_user)模块, 然后又加入了一个 ...
- 欢迎来到 Flask 的世界
欢迎来到 Flask 的世界 欢迎阅读 Flask 的文档.本文档分成几个部分,我推荐您先读 < 安装 >,然后读< 快速上手 >.< 教程 > 比快速上手文档更详 ...
随机推荐
- 【spring源码系列】之【Bean的销毁】
以"冬奥之光,多彩冰灯"为主题的第四十一届全国专业冰雕比赛在冰城哈尔滨市进入第二天,60名冰雕高手在哈尔滨冰灯艺术游园会园区展开激烈的竞技比拼. 冰雕艺术 1. 概述 Bean的销 ...
- LeetCode-094-二叉树的中序遍历
二叉树的中序遍历 题目描述:给定一个二叉树的根节点 root ,返回它的 中序 遍历. 示例说明请见LeetCode官网. 来源:力扣(LeetCode) 链接:https://leetcode-cn ...
- jmeter之如何减负-实现稳定超高并发测试(性能调优)之正确添加监听器
jmeter之如何减负-实现稳定超高并发测试(性能调优)在测试过程中,初学者使用工具不当,添加众多监控组件,非常想看到实时报告,跑不了一会,jmeter就卡死,只得重启 下面来总结下如何正确使用jme ...
- Java:基于AOP的动态数据源切换(附源码)
1 动态数据源的必要性 我们知道,物理服务机的CPU.内存.存储空间.连接数等资源都是有限的,某个时段大量连接同时执行操作,会导致数据库在处理上遇到性能瓶颈.而在复杂的互联网业务场景下,系统流量日益膨 ...
- 线程的sleep()方法和yield()方法有什么区别?
sleep()方法和yield()方法的区别: sleep()方法给其他线程运行机会时,不考虑线程的优先级,因此会给低优先级的线程运行机会:yield()方法只会给相同优先级或更高优先级的线程运行机会 ...
- Java程序员必备的工具和框架
最近几年,Java 的技术栈发展的非常快,成百上千的技术工具正不断地涌出来,这也造成了一个问题: 我们作为开发者,到底应该选哪些工具搭建出最合适的技术栈呢? 今天我就推荐一波我常用的.我了解的工具和框 ...
- ubuntu21.10搭建jenkins和gitlab自动化部署环境
镜像下载.域名解析.时间同步请点击阿里云开源镜像站 前置环境: vmware pro 16 + ubuntu21.10 安装gitlab 搭建ssh远程 打开终端 sudo apt-get insta ...
- 4月13日 python学习总结 组合与封装
一.组合 解决类与类之间代码冗余问题有两种解决方案:1.继承 2.组合 1.继承:描述的是类与类之间,什么是什么的关系 2.组合:描述的是类与类之间的关系,是一种什么有什么关系 一个类产生的 ...
- 【Vulnhub】LazySysAdmin
下载链接 https://download.vulnhub.com/lazysysadmin/Lazysysadmin.zip 运行环境 Virtualbox Vnware Workstation p ...
- 2、DTO(数据传输对象)
DTO:Data Transfer Object 即数据传输对象. 有些人会问这个DTO是干嘛的,不是已经有了Model实体类了么? 首先说一下,DTO是干嘛了.DTO的引入,应该说是伴随着分层架构设 ...