终端脚本命令
在flask1.1版本之前版本中都是采用flask-script模块来执行终端脚本命令,flask1.1版本以后不再使用这个模块了,因为存在兼容性问题。
flask1.0的终端命令使用
flask-script模块的作用可以让我们通过终端来控制flask项目的运行,类似于django的manage.py
官方文档:https://flask-script.readthedocs.io/en/latest/
安装命令:
bash
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,代码:
python
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()
启动终端脚本的命令:
python
# 端口和域名不写,默认为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 还可以为当前应用程序添加脚本命令
python
1. 引入Command命令基类
2. 创建命令类必须直接或间接继承Command,并在内部实现run方法或者__call__()方法,
同时如果有自定义的其他参数,则必须实现get_options方法或者option_list属性
3. 使用flask_script应用对象manage.add_command对命令类进行注册,并设置调用终端别名。
manage.py,代码:
python
from abc import ABC
from flask import Flask
from flask_script import Manager, Command, Option
app = 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()
使用效果:
bash
(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/
bash
pip install -U flask==2.0.2
安装了flask2.0以后,当前项目所在的python环境就提供了一个全局的flask命令,这个flask命令是Click提供的。
bash
# 要使用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命令提供的子命令。
bash
flask routes # 显示当前项目中所有路由信息
flask run # 把flask项目运行在内置的测试服务器下
# flask run --host=0.0.0.0 --port=5055
flask shell # 基于项目的应用上下文提供终端交互界面,可以进行代码测试。
Click自定义终端命令
python
import click
from flask import Flask, views
app = 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
"""
终端下的运行效果:
bash
(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
代码:
python
import click, os
from flask import Flask
app = 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}目录已存在!请先处理完成以后再创建。")
return
os.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()
终端调用:
bash
flask startapp home
flask startapp users
Jinja2模板引擎
Flask内置的模板语言Jinja2,它的设计思想来源于 Django 的模板引擎DTP(DjangoTemplates),并扩展了其语法和一系列强大的功能。
- Flask提供的 render_template 函数封装了该模板引擎Jinja2
- render_template 函数的第一个参数是模板的文件名,后面的参数都是键值对,表示模板中变量对应的数据值。
模板基本使用
-
在flask应用对象创建的时候,设置或者保留template_folder参数,创建模板目录
pythonapp = Flask(__name__,template_folder='templates')
-
在项目下手动创建
templates
文件夹,用于存放所有的模板文件,并在目录下创建一个模板html文件index.html
django<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ title }}</title> </head> <body> <h1>{{ content }}</h1> </body> </html>
-
在视图函数设置渲染模板并设置模板数据
pythonfrom 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()
输出变量
{{ 变量名 }},这种 {{ }} 语法叫做 变量代码块
视图代码:
python
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()
模板代码
jinja2
<!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()转换为一个字符串就可以,比如,可以通过下面的方式显示一个字典或者列表中的某个元素:
视图代码:
python
from flask import Flask, render_template
app = 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)
模板代码:
jinja2
<!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中被渲染出来
jinja2
{# <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对象:
jinja2
<p>{{ config.ENV }}</p>
<p>{{ config.DEBUG }}</p>
request
就是flask中代表当前请求的request对象:
jinja2
<p>{{ request.url }}</p>
<p>{{ request.path }}</p>
<p>{{ request.method }}</p>
session
为Flask的session对象,显示session数据
jinja2
{{session.new}}
False
g变量
在视图函数中设置g变量的 name 属性的值,然后在模板中直接可以取出
jinja2
{{ g.name }}
url_for()
url_for会根据传入的路由器函数名,返回该路由对应的URL,在模板中始终使用url_for()就可以安全的修改路由绑定的URL,则不比担心模板中渲染出错的链接:
jinja2
{{url_for('home')}}
如果我们定义的路由URL是带有参数的,则可以把它们作为关键字参数传入url_for(),Flask会把他们填充进最终生成的URL中:
jinja2
{{ url_for('index', id=1)}}
/index/1 {# /index/<int:id> id被声明成路由参数 #}
/index?id=1 {# /index id被声明成路由参数 #}
课堂代码:
主程序 manage.py:
python
from flask import Flask, render_template,g
app = 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:
jinja2
<!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>