终端脚本命令
在flask1.1版本之前版本中都是采用flask-script模块来执行终端脚本命令,flask1.1版本以后不再使用这个模块了,因为存在兼容性问题。
flask1.0的终端命令使用
flask-script模块的作用可以让我们通过终端来控制flask项目的运行,类似于django的manage.py
官方文档:https://flask-script.readthedocs.io/en/latest/
安装命令:
pip install -U flask==1.1.4
pip install flask-script -i https://pypi.douban.com/simple
集成 Flask-Script到flask应用中,创建一个主应用程序,一般我们叫manage.py/run.py/main.py
都行。
manage.py,代码:
from flask import Flas app = Flask(__name__)"""使用flask_script启动项目"""
from flask_script import Manager
manage = Manager(app)@app.route('/')
def index():return 'hello world'if __name__ == "__main__":manager.run()
启动终端脚本的命令:
# 端口和域名不写,默认为127.0.0.1:5000
python manage.py runserver# 通过-h设置启动域名,-p设置启动端口 -d
python manage.py runserver -h0.0.0.0 -p8888 # 关闭debug模式
python manage.py runserver -h0.0.0.0 -p8888 -d # 开启debug模式# 进入flask交互终端,在这个终端下,可以直接调用flask代码进行测试。
python manage.py shell
自定义终端命令
Flask-Script 还可以为当前应用程序添加脚本命令
1. 引入Command命令基类
2. 创建命令类必须直接或间接继承Command,并在内部实现run方法或者__call__()方法,同时如果有自定义的其他参数,则必须实现get_options方法或者option_list属性
3. 使用flask_script应用对象manage.add_command对命令类进行注册,并设置调用终端别名。
manage.py,代码:
from abc import ABCfrom flask import Flask
from flask_script import Manager, Command, Optionapp = Flask(__name__)
# 配置
app.config.update({"DEBUG": False,"SECRET_KEY": "sklaasle3k2334"
})"""使用flask_script启动项目"""
manager = Manager(app)class PrintCommand(Command, ABC):"""命令的相关描述: 打印数据"""def get_options(self):options = (# Option('简写选项名', '参数选项名', dest='变量名', type=数据类型, default="默认值"),Option('-h', '--host', dest='host', type=str, default="127.0.0.1"),Option('-p', '--port', dest='port', type=int, default=8000),Option('-d', '--debug', dest='debug', type=bool, default=False))# 必须返回选项return options# 也可以使用option_list来替代get_options# option_list = (# Option('-h', '--host', dest='host', type=str, default="127.0.0.1"),# Option('-p', '--port', dest='port', type=int, default="7000"),# Option('-d', '--debug', dest='debug', type=bool, default=False)# )# 没有flask的应用实例对象---->app对象# def run(self, host, port, debug):# print("测试命令")# print(f"self.host={host}")# print(f"self.port={port}")# print(f"self.debug={debug}")def __call__(self, app, host, port, debug): # 会自动传递当前flask实例对象进来print("测试命令")print(f"self.host={host}")print(f"self.port={port}")print(f"self.debug={debug}")# manage.add_command("终端命令名称", 命令类)
manager.add_command("print", PrintCommand)@app.route("/")
def index():return "ok"if __name__ == '__main__':manager.run()
使用效果:
(flask) moluo@ubuntu:~/Desktop/flaskdemo$ python manage.py print -h=0.0.0.0 -p 8000
测试命令
self.host=0.0.0.0
self.port=8000
self.debug=False(flask) moluo@ubuntu:~/Desktop/flaskdemo$ python manage.py print -h=0.0.0.0 -p 8000 -d=true
测试命令
self.host=0.0.0.0
self.port=8000
self.debug=True(flask) moluo@ubuntu:~/Desktop/flaskdemo$ python manage.py print -h=0.0.0.0 -d=true
测试命令
self.host=0.0.0.0
self.port=8000
self.debug=True
flask2.0的终端命令使用
flask0.11.0版本以后,flask内置了一个Click模块,这个模块是终端命令模块,可以让我们直接通过Click的装饰器,编写和运行一些终端命令。在flask2.0版本已经不能兼容flask-script模块了,所以需要改成使用Click模块来运行和自定义管理终端命令了。
文档地址:https://dormousehole.readthedocs.io/en/latest/cli.html#id10
click文档:https://click.palletsprojects.com/en/8.0.x/
pip install -U flask==2.0.2
安装了flask2.0以后,当前项目所在的python环境就提供了一个全局的flask命令,这个flask命令是Click提供的。
# 要使用Click提供的终端命令flask,必须先在环境变量中声明当前flask项目的实例对象所在的程序启动文件。
# 例如:manage.py中使用了 app = Flask(__name__),则manage.py就是程序启动文件# 使用flask终端命令之前,可以配置2个环境变量。
# 指定入口文件,开发中入口文件名一般:app.py/run.py/main.py/index.py/manage.py/start.py
export FLASK_APP=manage.py
# 指定项目所在环境
export FLASK_ENV=development # 开发环境,默认开启DEBUG模式
# export FLASK_ENV=production # 生成环境,默认关闭DEBUG模式
默认情况下,flask命令提供的子命令。
flask routes # 显示当前项目中所有路由信息
flask run # 把flask项目运行在内置的测试服务器下
# flask run --host=0.0.0.0 --port=5055
flask shell # 基于项目的应用上下文提供终端交互界面,可以进行代码测试。
Click自定义终端命令
import click
from flask import Flask, viewsapp = Flask(__name__)
# 配置
app.config.update({"DEBUG": False,
})# 自定义终端命令
@app.cli.command("faker") # 假设这个用于生成测试数据
@click.argument("data", default="user") # data表示生成数据的类型[参数argument是命令调用时的必填参数]
@click.option('-n', 'number', type=int, default=1, help='生成的数据量.') # num表示测试数据的生成数量[选项option是命令调用时的可选参数]
def faker_command(data, number):"""添加测试信息"""print("添加测试信息")print(f"数据类型:data={data}")print(f"生成数量:number={number}")@app.route("/")
def index():return "ok"if __name__ == '__main__':app.run()"""
flask faker --help
flask faker -n10 user
flask faker user
"""
终端下的运行效果:
(flask) moluo@ubuntu:~/Desktop/flaskdemo$ flask faker -n10 user
添加测试信息
数据类型:data=user
生成数量:number=10
(flask) moluo@ubuntu:~/Desktop/flaskdemo$ flask faker user
添加测试信息
数据类型:data=user
生成数量:number=1
(flask) moluo@ubuntu:~/Desktop/flaskdemo$ flask faker goods
添加测试信息
数据类型:data=goods
生成数量:number=1
练习:
1. flask2.0的终端下,输入 python manage.py startapp home 则可以在当前目录下创建以下目录和文件
项目目录/└── home├── views.py├── models.py├── urls.py└── tests.py
代码:
import click, os
from flask import Flaskapp = Flask(__name__)
# 配置
app.config.update({"DEBUG": False
})@app.cli.command("startapp")
@click.argument("name")
# @click.option('-n', 'name', help='app name')
def startapp(name):"""生成子模块或子应用"""if os.path.isdir(name):print(f"当前{name}目录已存在!请先处理完成以后再创建。")returnos.mkdir(name)open(f"{name}/views.py", "w")open(f"{name}/models.py", "w")open(f"{name}/documents.py", "w")open(f"{name}/ws.py", "w")open(f"{name}/services.py", "w")open(f"{name}/urls.py", "w")open(f"{name}/test.py", "w")print(f"{name}子应用创建完成....")@app.route("/")
def index():return "ok"if __name__ == '__main__':app.run()
终端调用:
flask startapp home
flask startapp users
Jinja2模板引擎
Flask内置的模板语言Jinja2,它的设计思想来源于 Django 的模板引擎DTP(DjangoTemplates),并扩展了其语法和一系列强大的功能。
- Flask提供的 render_template 函数封装了该模板引擎Jinja2
- render_template 函数的第一个参数是模板的文件名,后面的参数都是键值对,表示模板中变量对应的数据值。
模板基本使用
-
在flask应用对象创建的时候,设置或者保留template_folder参数,创建模板目录
app = Flask(__name__,template_folder='templates')
-
在项目下手动创建
templates
文件夹,用于存放所有的模板文件,并在目录下创建一个模板html文件index.html
<!doctype html> <html lang="en"> <head><meta charset="UTF-8"><title>{{ title }}</title> </head> <body><h1>{{ content }}</h1> </body> </html>
-
在视图函数设置渲染模板并设置模板数据
from flask import Flask, render_template# 默认情况下,flask默认直接支持视图加载模板的。 # Flask类在实例化的时候,默认当前根目录下的templates目录作为模板目录 app = Flask(__name__, template_folder="templates") # 配置 app.config.update({"DEBUG": True })@app.route("/") def index():data = {"title": "我的模板标题","content": "我的模板内容"}return render_template("index.html", **data)@app.route("/user/<id>") def user(id):title = "User Center"content = "我的个人中心"print(locals()) # {'id': '100', 'title': 'User Center', 'content': '我的个人中心'}return render_template("user.html", **locals())if __name__ == '__main__':app.run()
输出变量
{{ 变量名 }},这种 {{ }} 语法叫做 变量代码块
视图代码:
import click
from flask import Flask,render_template
# flask开发小型的项目,直接在当前flask应用配置即可。手动创建模板目录。
# flask开发中大型项目,直接在当前flask的每一个子应用(蓝图)下构建目录。
app = Flask(import_name=__name__, template_folder="templates")# 配置类
class Config(object):DEBUG = True # 开启调试模式# 加载配置
app.config.from_object(Config)@app.route("/")
def index():title = "站点标题"user_list = [{"id":1, "name": "xiaoming", "age":16},{"id":2, "name": "xiaoming", "age":16},{"id":3, "name": "xiaoming", "age":16},]return render_template("index.html", **locals())if __name__ == '__main__':app.run()
模板代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>{{title}}</title>
</head>
<body><h1>{{title}}</h1><p>{{ user_list.0 }}</p><p>{{ user_list.0.name }}</p>
</body>
</html>
pycharm中设置当前项目的模板语言:
files/settings/languages & frameworks/python template languages。
设置下拉框为jinja2,保存
设置指定目录为模板目录,鼠标右键->Mark Directory as …-> Template Folder
Jinja2 模版中的变量代码块的输出的内容可以是Python的任意类型数据或者对象,只要它能够被 Python 的 __str__
方法或者str()转换为一个字符串就可以,比如,可以通过下面的方式显示一个字典或者列表中的某个元素:
视图代码:
from flask import Flask, render_templateapp = Flask(__name__, template_folder="templates")@app.route("/")
def index():title = "我的flask"data_list = ["a", "b", "c"]data_dict = {"name": "xiaoming","id": 100,}user_list = [{"id":1, "name": "xiaoming", "age":16},{"id":2, "name": "xiaoming", "age":16},{"id":3, "name": "xiaoming", "age":16},]return render_template("index.html", **locals())if __name__ == '__main__':app.run(host="0.0.0.0", port=5000, debug=True)
模板代码:
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><title>{{ title }}</title>
</head>
<body><h1>{{ title }}!!</h1><p>{{ data_list }}</p><p>{{ data_list.1 }}</p><p>{{ data_list[-1]}}</p><p>{{ data_list | last }}</p><p>{{ data_list | first }}</p><p>{{ data_dict }}</p><p>{{ data_dict.name }}</p><p>{{ user_list.0 }}</p><p>{{ user_list.0.name }}</p>
</body>
</html>
使用 {# #} 进行注释,注释的内容不会在html中被渲染出来
{# <h1>{{ title }}!!</h1>#}
{# <p>{{ data_list }}</p>#}
{# <p>{{ data_list.1 }}</p>#}<p>{{ data_list[-1]}}</p><p>{{ data_list | last }}</p><p>{{ data_list | first }}</p><p>{{ data_dict }}</p><p>{{ data_dict.name }}</p><p>{{ user_list.0 }}</p>
{# <p>{{ user_list.0.name }}</p>#}
模板中内置的变量和函数
你可以在自己的模板中访问一些 Flask 默认内置的函数和对象
config
你可以从模板中直接访问Flask当前的config对象:
<p>{{ config.ENV }}</p><p>{{ config.DEBUG }}</p>
request
就是flask中代表当前请求的request对象:
<p>{{ request.url }}</p><p>{{ request.path }}</p><p>{{ request.method }}</p>
session
为Flask的session对象,显示session数据
{{session.new}}
False
g变量
在视图函数中设置g变量的 name 属性的值,然后在模板中直接可以取出
{{ g.name }}
url_for()
url_for会根据传入的路由器函数名,返回该路由对应的URL,在模板中始终使用url_for()就可以安全的修改路由绑定的URL,则不比担心模板中渲染出错的链接:
{{url_for('home')}}
如果我们定义的路由URL是带有参数的,则可以把它们作为关键字参数传入url_for(),Flask会把他们填充进最终生成的URL中:
{{ url_for('index', id=1)}}
/index/1 {# /index/<int:id> id被声明成路由参数 #}
/index?id=1 {# /index id被声明成路由参数 #}
课堂代码:
主程序 manage.py:
from flask import Flask, render_template,gapp = Flask(__name__, template_folder="templates")@app.route("/")
def index():g.name = "xiaohei"title = "我的flask"data_list = ["a", "b", "c"]data_dict = {"name": "xiaoming","id": 100,}user_list = [{"id":1, "name": "xiaoming", "age":16},{"id":2, "name": "xiaoming", "age":16},{"id":3, "name": "xiaoming", "age":16},]return render_template("index.html", **locals())@app.route("/user/<int:uid>")
def user(uid):print(uid)return f"uid={uid}"if __name__ == '__main__':app.run(host="0.0.0.0", port=5000, debug=True)
模板 templates/index.html:
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><title>{{ title }}</title>
</head>
<body>
{# <h1>{{ title }}!!</h1>#}
{# <p>{{ data_list }}</p>#}
{# <p>{{ data_list.1 }}</p>#}<p>{{ data_list[-1]}}</p><p>{{ data_list | last }}</p><p>{{ data_list | first }}</p><p>{{ data_dict }}</p><p>{{ data_dict.name }}</p><p>{{ user_list.0 }}</p>
{# <p>{{ user_list.0.name }}</p>#}<p>{{ config.ENV }}</p><p>{{ config.DEBUG }}</p><p>{{ request.url }}</p><p>{{ request.path }}</p><p>{{ request.method }}</p><p>{{ session.new }}</p><p>{{ g.name }}</p><p>{{ url_for("user", uid=3) }}</p> {# /user/3 #}</body>
</html>