Flask
1、Flask用法
**视图**
处理业务逻辑代码的函数
**路由**
发送网络请求的URL地址
**Flask框架**
- 轻量级的web后台框架
- werkzeug(路由模块)
- 模版引擎 Jinja2
- 其他功能需要第三方扩展实现
1.1、常用扩展包
Flask_SQLalchemy  ORM操作数据库
Flask-RESTful  开发restful的工具
Flask-Session    Session存储
Flask-Migrate  管理迁移数据库
Flask-cache  缓存
Flask-WTF  表单
Flask-Mail  邮箱
Flask-Login  认证用户状态
Flask-OpenID  认证
Flask-admin  简单而可扩展的管理接口框架
Flask-Bable 提供国际化和本地化支持-翻译
1.2、最小应用
from flask import Flask
# __name__表示当前文件所在的目录就是Flask项目目录 会在项目目录寻找静态文件夹和模版文件夹
app = Flask(__name__)
if __name__ == '__main__':
    # app.run()
    # 可选参数
    app.run(host='0.0.0.0', port=8888, debug=True)
@app.route('/')
def index():
    return 'Hello Flask'
1.3、Flask两种启动方式
以下两种方式启动,即可不需要main函数
命令行运行
export  FLASK_APP=xx.py
export FLASK_ENV=development
flask run -h 0.0.0.0 -p 8888
pycharm配置运行

旧版本pycharm
Script path: 脚本路径
Parameters: -m flask run -h 0.0.0.0 -p 8888
1.4、路由
- 通过app.url_map 即可查看路由信息
Map([
<Rule '/index' (OPTIONS, GET, HEAD) -> index>,
 <Rule '/static/<filename>' (OPTIONS, GET, HEAD) -> static>
])
- 设置请求方式 get、post
@app.route('/index', methods=['get', 'post'])
def index():
    print(app.url_map)
    return 'Hello Flask'
1.4.1、路由变量
# 变量名称和形参名称必须一致
@app.route('/useradd/<userid>')
def useradd(userid):
    print('userid', userid)
1)、转换器
设置传递的参数的类型。
int、string、float、uuid。
# int 为转换器名称,非数据类型
@app.route('/useradd/<int:userid>')
转换器都是基于from werkzeug.routing import BaseConverter
2)、自定义转换器
from werkzeug.routing import BaseConverter
class MobileConverter(BaseConverter):
    regex = r"1[3-9]\d{9}$"
# 将自定义的转换器类,注册到系统默认的转换器字典中
app.url_map.converters['mob'] = MobileConverter
@app.route('/userad/<mob:mobile>')
def userad(mobile):
    print(mobile)
1.5、请求request
1.5.1、request参数获取
from flask import request
1、localhost:8000/user/zhangsan/22  
2、localhost:8000/user?name=zs&age=12  GET请求
request.args获取
request.args.get("")
# 3、表单参数
{"name":"zhangsan","age":21} POST请求
request.form获取
request.form.get("")
# 4、json字符串
'{"name":"zhangsan","age":21}'
request.json获取
json字符串转换为字典json.loads()
# 5、文件类型参数
request.files获取
fimg = request.files['img']  # type:FileStorage  类型声明,有提示
fimg.save("1.png")
1.6、响应
1.6.1、访问静态资源
静态资源默认目录为static。
修改静态资源目录
app = Flask(__name__,
                     static_folder="static1",
                     static_url_path=“res/img”
)
# 访问路径
localhost:8080/res/img/12.png
1.6.2、返回模版文件
新建templates目录
@app.route('/')
def index():
    return render_template('index.html')
1.6.3、返回响应数据
- 返回3个值,也就是元祖集合,分别是响应体、响应状态码、响应头。
- 自定义响应对象Response
from flask import Response,make_response
# 创建响应对象
response=make_response("hello flask")
# 设置响应头
response.headers['B']=10
return response
1.6.4、返回json
可直接使用flask自带的jsonify()生成json响应。
dict={"name":"zhangdan","age":22}
return jsonify(dict1)
# return jsonify(name="zs",age=22) 也支持关键字实参的形式
1.6.5、重定向redirect
# 重定向到自己的路由,只需要url资源段
return redirect("/index")
1.7、状态保持与异常捕获
1.7.1、Cookie
特点
- 数据保存在客户端,减轻服务器压力
- 访问网站时,浏览器自动将cookie传给服务器
@app.route('/')
def index():
    resp = make_response()
    # 设置cookie内容
    resp.set_cookie('per_page', '10', max_age=86400)
    # 删除cookie,本质设置max_age=0
    # resp.delete_cookie("per_page")
    return resp
1.7.2、Session
特点
- 存储在服务端(服务器的数据库中)
from flask import session
from datetime import timedelta
app = Flask(__name__)
# 使用flask里面的session需要设置加密字符串
app.secret_key = "sdsd232sdd34dfgdfg"
# 设置session有效期
app.permanent_session_lifetime = timedelta(days=1)
@app.route('/index')
def index1():
    # 设置session
    session["names"] = "jack"
    # 使有效期生效
    session.permanent = True
    # 获取session
    session.get("names")
    # 删除session
    session.pop("names")
    session.clear()
    return "ok"
1.7.3、状态保持jwt
Json Web Token。本质是一个字符串,将用户信息保存在json字符串中,编码后得到JWT token,且带有签名信息,接收后可以检验是否被篡改。
token身份验证流程
1、客户端使用用户名和密码请求登录
2、服务端接收到用户名和密码,进行验证
3、验证成功,服务端签发一个token,返回给客户端
4、客户端存储起来,放到比如cookie里
5、客户端每次请求都需要携带token,可以在cookie或header中携带
6、服务端收到请求,验证token,向客户端返回请求数据
优点
- 支持跨域,cookie是无法跨域的
- 无状态,服务端不需要存储session信息,减轻服务器压力
- 更适用于CDN
- 适用于移动端
- 无需考虑CSRF,不依赖cookie,不会出现CSRF
pip install pyjwt
flask实现jwt
import jwt
from datetime import timedelta, datetime
@app.route("/login")
def login():
    # 格林威治0时区当前时间+2h
    expire = datetime.utcnow() + timedelta(hours=2)
    # 构建载荷信息
    user_dict = {
        "user_id": 22,
        "username": "xiaoming",
        "exp": expire  # 过期时间戳 2小时
    }
    # 构建密钥
    key = "python3"
    # 生成2小时有效token
    token = jwt.encode(payload=user_dict, key=key, algorithm="HS256")
    # token = token.decode()
    resp = make_response()
    resp.headers['Authorization'] = token
    return resp
    return "login success {}".format(token)
@app.route("/index")
def index():
    # 提取请求头中的token
    print(request.headers)
    token = request.headers.get("Authorization")
    # 校验token 获取载荷信息
    payload = jwt.decode(token, key="python3", algorithms="HS256")
    username = payload.get("username")
    user_id = payload.get("user_id")
    return "用户ID:{},用户名:{}".format(user_id, username)
增加JWT安全性
- JWT是在请求头中传递的,避免网络劫持,推荐使用https
- JWT的hash签名密钥保存在服务端,保证服务端不被攻破,理论上就是安全的
- JWT可以使用暴力穷举来破解,定期更换服务端的hash密钥(也就是salt)
1.7.4、异常捕获
flask对http进行了封装,可以捕获http错误,也可主动抛出http错误。
from flask import Flask, abort
# 重写404
@app.errorhandler(404)
def error_404(error):  # 一旦捕获,要求必须定义形参接收具体错误信息
    return "访问的页面不存在"
# 捕获系统内置错误
@app.errorhandler(ZeroDivisionError)
def error_zone(error):
    return "除数不能为0"
@app.route("/")
def index():
    # abort(404)
    # abort(500)
    a = 1 / 0
    return ""
2、高级用法
2.1、Flask请求钩子
请求钩子可以对请求的各个阶段进行监听,方便对请求完成统一的处理,减少重复代码,类似于Django的中间件。
1、before_request
- 每次执行视图函数之前调用
- 对请求进行准备处理
- 如果在该函数返回响应,视图函数将不会被调用
2、after_request
- 没有抛出异常,在每次视图函数之后之后调用
- 在此函数中对响应值进行近一步修改处理
- 接收一个参数,即包装好的响应对象
- 将修改后的响应对象返回
3、before_first_request
- web应用在第一次请求前被调用
- 进行web应用的初始化操作
4、teardown_request
- 每次执行视图函数之后调用
- 无论是否异常都会执行,一般用于请求收尾
- 接受一个参数,错误信息
- 需要在非调试模式下运行
- 在after_request之后执行
代码实现
@app.before_first_request # 1
def before_first_request():
    print('before_first_request')
@app.before_request # 2
def before_request():
    print('before_request')
@app.after_request # 3
def after_request(response):
    print('after_request')
    return response
@app.teardown_request # 4
def teardown_request(e):
    print('teardown_request')
装饰器的两种执行方式
方法1:语法糖
@app.teardown_request
方法2:装饰器理解为函数
def index():
    pass
app.teardown_request(index)
2.2、蓝图
实现flask项目的模块化。
蓝图实现步骤
- 1、创建蓝图对象,管理子模块
新建python package=>home,修改__init__.py
from flask import Blueprint
# 设置蓝图名称,导包路径  
# url_prefix  默认访问路径前缀/home/index
home_bp = Blueprint("home", __name__,url_prefix="/home")
from home import views
- 2、使用蓝图对象绑定路由和视图函数
from home import home_bp
@home_bp.route("/index")
def index():
    return "home_page"
- 3、在app中注册蓝图对象
from home import home_bp
app = Flask(__name__)
app.register_blueprint(home_bp)
蓝图其他使用
- 可以使用请求钩子函数,作用域在模块中
- url_for 反解析url url_for("蓝图.函数名") 可得到url
2.3、上下文
是一个数据容器,保存了Flask程序运行过程中的一些信息。
2种:请求上下文和应用上下文。
2种上下文使用范围相同,从请求开始到结束,范围外会失效。
线程隔离。
2.3.1、请求上下文
记录和请求相关的数据,包括request和session 2个变量。
- request 封装了http请求的内容,针对的是http请求。
手动开启请求上下文
with app.request_context():
    print(request)
- session 记录请求会话中的信息,针对的是用户信息。
2.3.2、应用上下文
记录和应用相关的数据,包括current_app和g两个变量
- current_app 自动引用创建的Flask对象,需要在项目其他文件中使用app时,应该通过current_app来获取,减少循环导入的问题。
手动开启应用上下文
with app.app_context():
    print(current_app)
- g
- flask 会给开发者预留一个容器,记录自定义数据
- g变量每次请求会重置数据
- g使用场景,1)、在钩子函数和视图函数之间传递数据(钩子函数获取信息g.name,然后视图函数g.name获取) 2)、函数嵌套时传递数据
 
2.4、用户认证案例
2.4.1、统一处理
在钩子函数before_request中统一提取用户信息,保存在g中。视图函数即可获取。
2.4.2、用户权限认证
- 某些功能未登录无法访问,首页未登录显示登录标签。
- 使用装饰器,先装饰路由,再装饰验证
from  functools import wraps
# 验证登录的装饰器
def login_requires(view_func):
    # 防止装饰器修改被装饰函数的函数名和文档信息
    @wraps(view_func)
    def wrapper(*args, **kwargs):
        # 判断是否登录的逻辑
        if g.name:
            # 已登录
            return view_func(*args, **kwargs)
        else:
            # 权限验证失败
            abort(401)
    return wrapper
@app.route("/index")
@login_requires
def index():
    return "首页展示"
2.5、Flask应用配置
2.5.1、加载配置
2.5.1.1、app.config
# app.config,用于设置配置,该属性继承dict
app.config["PERMANENT_SESSION_LIFETIME"]=timedelta(days=7)
app.config["DEBUG"]=True
app.config["SECRET_KEY"]="xxx"
app.config["JSON_AS_ASCII"]=False
2.5.1.2、config.py
# 对象中加载配置config.py
# 各种环境配置文件,开发、生产、测试多套环境
from datetime import timedelta
class BaseConfig:
    PERMANENT_SESSION_LIFETIME = timedelta(days=7)
    SECRET_KEY = "xxx"
    JSON_AS_ASCII = False
class DevelopmentConfig(BaseConfig):
    """开发环境"""
    DEBUG = True
    SQL_URL = "127.0.0.1"
    SQL_PORT = 3306
class ProductConfig(BaseConfig):
    """生产环境"""
    DEBUG = False
    SQL_URL = "192.168.1.1"
    SQL_PORT = 3306
    SQL_PORT_SLAVE = 3366
class TestConfig(BaseConfig):
    """测试环境"""
    DEBUG = True
    TESTING = True
CHO_ENV = {
    "dev": DevelopmentConfig,
    "pro": ProductConfig,
    "test": TestConfig,
}
使用config.py文件
配置类中读取
from config import  ProductConfig,DevelopmentConfig,TestConfig
app.config.from_object(ProductConfig)
或者
from config import CHO_ENV
app.config.from_object(CHO_ENV.get("env"))
环境变量中读取
app.config.from_envvar()
配置py文件中读取
app.config.from_pyfile()
2.5.2、切换配置
虽然封装了多套环境,但是需要修改代码才可以切换配置,不方便开发和测试。
推荐做法:
- 定义工厂函数,封装应用的创建过程
- 利用环境变量,调用工厂函数,指定配置并动态创建应用
def create_app(config_name):
    """工厂方法"""
    app = Flask(__name__)
    app.config.from_object(CHO_ENV[config_name])
    return app
app = create_app("dev")
# app = create_app("pro")
# 根据不同的传入参数 得到不同的app
2.5.3、加载隐私配置
从环境变量中加载配置,可用于加载隐私配置。
- 通过环境变量指定配置文件的路径
- export ENV_CONFIG="配置文件路径"
- slient=True 即使未配置环境变量也不会报错
- app.config.from_envvar("ENV_CONFIG",slient=True)
2.6、Flask-restful
2.6.1、视图
环境安装
pip install flask-restful
2.6.1.1、构建RESTAPI
from flask_restful import Api, Resource
def create_app(config_name):
    """工厂方法"""
    app = Flask(__name__)
    app.config.from_object(CHO_ENV[config_name])
    return app
app = create_app("dev")
# 1、创建组件对象
api = Api(app)
# 2、定义类视图
class DemoResource(Resource):
    def get(self):
        # 返回字典,最底层将字典转换为json字符串
        return {"get": "get message"}
    def post(self):
        return "post"
# 3、类视图添加路由信息
# api.add_resource(DemoResource, '/', endpoint="类视图别名")
api.add_resource(DemoResource, '/index')
if __name__ == '__main__':
    app.run(debug=True, port=8888, host="0.0.0.0")
2.6.1.2、Restful给类视图添加装饰器
- 装饰器装饰顺序按照列表9-0
 1、给类视图所有方法添加装饰器
def my_decrot(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper
def my_decrot2(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper
app = Flask(__name__)
api = Api(app)
class DemoResource(Resource):
    # 装饰器
    method_decorators = [my_decrot, my_decrot]
    def get(self):
        return {"get": "get message"}
    def post(self):
        return "post"
2、类视图指定方法添加指定装饰器
    method_decorators = {
        "get": [my_decrot, my_decrot2],
        "post": [my_decrot2],
    }
2.6.1.3、蓝图和类视图
配合使用的步骤
# 1、创建蓝图对象
蓝图对象 = Blueprint("蓝图名",__name__)
# 2、每个蓝图创建组件对象
组件对象 = Api(蓝图对象)
# 3、组件对象添加类视图
组件对象.add_resource(viewResource,'url路由')
具体案例
# 1、蓝图/__init__.py
from flask import Blueprint
from flask_restful import Api
from . import views
# 设置蓝图名称,导包路径
home_bp = Blueprint("home", __name__, url_prefix="/home")
home_obj = Api(home_bp)
home_obj.add_resource(views.HomeResource, '/index')
from home import views
# 2、蓝图/views.py
from flask_restful import Resource
class HomeResource(Resource):
    def get(self):
        return {"get": "get msg"}
    def post(self):
        return {"post": "post msg"}
2.6.2、请求
2.6.2.1、请求解析
- 序列化器功能
 - 反序列化
 - 参数解析
 - 数据保存
 - 序列化
- flask-Resuful 实现了类似功能
 - 参数解析 RequestParser
 - 序列化 marshal函数
- flask-restful没有数据保存的功能,可通过flask-sqlalchemy扩展完成
参数解析RequestParser
# 1 、创建请求解析器
req_parse = RequestParser()
# 2、添加参数规则
req_parse.add_argument(参数名,参数规则...)
- default  给参数设置默认值
- required 必须传递,否则返回400,取值True或False
- location 设置参数提取位置  args/form/json/files/headers/cookies
- type 参数的转换类型或者格式校验
# 3、执行解析
参数对象 = req_parse.parse_args()
# 4、获取参数
参数对象.参数名
from flask_restful import Resource
from flask_restful.reqparse import RequestParser
class HomeResource(Resource):
    def get(self):
        rpa = RequestParser()
        rpa.add_argument("name", type=str, location="args")
        rpa.add_argument("age", type=int, location="args")
        ret = rpa.parse_args()
        print(ret.get("name"))
        return {"get": "get msg"}
# 访问地址
localhost:8888/index?name=zs&age=22
2.6.3、响应
2.6.3.1、序列化marshal函数
# 定义序列化规则
序列化规则 = (字段名:序列化类型)
# marshal按照序列化规则,将模型转换为字典
序列化后的字典 = marshal(模型对象,序列化规则)
常见的序列化类型
- String 转换字符串类型属性
- Integer 整数
- Float 浮点
- List 列表,要求列表元素类型一致
- Nested 字典类型
- Boolean 布尔类型
代码实现
- 方法1 marshal
点击查看代码
from flask_restful import fields, marshal
# 1、模型类
class User(object):
    def __init__(self):
        self.name = "zs"
        self.age = 12
        self.height = 175.5
        self.mylist = [20, 30, 40]
        self.mydict = {
            "a": 1,
            "c": True
        }
# 2、序列化规则字典
myshal_dict = {
    "name": fields.String(20),
    "age": fields.Integer(default=18),
    "height": fields.Float(),
    "mylist": fields.List(fields.Integer),
    "mydict": fields.Nested({
        "a": fields.Integer,
        "c": fields.Boolean,
    })
}
class HomeResource(Resource):
    def get(self):
        # 3、创建用户对象
        user = User()
        # 4、利用marshal函数,将对象序列化成字典
        mym = marshal(user, myshal_dict)
        return mym
- 方法2 marshal_with
点击查看代码
from flask_restful import fields,marshal_with
# 1、模型类(已经实例化)
class User(object):
    def __init__(self):
        self.name = "zs"
        self.age = 12
        self.height = 175.5
        self.mylist = [20, 30, 40]
        self.mydict = {
            "a": 1,
            "c": True
        }
# 2、序列化规则字典
myshal_dict = {
    "name": fields.String(20),
    "age": fields.Integer(default=18),
    "height": fields.Float(),
    "mylist": fields.List(fields.Integer),
    "mydict": fields.Nested({
        "a": fields.Integer,
        "c": fields.Boolean,
    })
}
class HomeResource(Resource):
    method_decorators = {
        "post": [marshal_with(myshal_dict)]
    }
    def post(self):
        user = User()
        return user
- 方法3 推荐
 在模型类定义转字典的方法
2.6.3.2、自定义json
- 字典转换json的方法,output_json,包裹成json返回。
- 复制output_json源码,使用装饰器api.representation(mediatype="application/json") # 返回参数类型
 - 拦截返回的字典数据,再在复制出来的output_json方法里进行修改
# output_json放到utils/output_json.py文件里
from util import output_json
api.representation(mediatype="application/json")(output_json)
# 下面的类视图都可以使用到
2.7、单例模式
单例--只需要初始化一个对象的方案。如数据库链接。
优点
- 只会保留一个对象,减少系统开销
- 提高创建速度,每次获取已经存在的对象,全局共享对象
- 在系统中只存在一个对象实例,避免多实例创建使用产生的逻辑错误
2.7.1、实现单例
1、重写__new__方法
class Singleton(object):
    # __new__方法在__init__方法调用前被调用
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            # 创建对象保存到类上,调用父类的方法
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
            # 业务内容 初始化
            # cls._instance.rest=REST(_serverIP,_serverPort,_softVersion)
            # cls._instance.rest.setAccount(_accountSid,_accountToken)
            # cls._instance.rest.setAppId(_appId)
            cls._instance.name = "zhangsan"
        return cls._instance
    def send_sms(self):
        # 执行发送
        result = self.name
        return ""
if __name__ == '__main__':
    s1 = Singleton()
    print(s1.send_sms())
    s2 = Singleton()
    print(id(s1))
    print(id(s2))
    # 同一个id
2、装饰器实现单例
# 装饰器实现单例
from threading import Lock
def singleton(cls):
    instance = {}
    instance_lock = Lock()
    def wrapper(*args, **kwargs):
        if cls not in instance:
            # 使用锁保证只创建一个对象
            with instance_lock:
                instance["cls"] = cls(*args, **kwargs)
        return instance(cls)
    return wrapper
@singleton
class Foo(object):
    def __init__(self):
        name = "zhangsan"
    def send_sms(self):
        result = self.name
        return ""
foo1 = Foo()
foo1.send_sms()
2.8、Flask-SQLALchemy扩展
2.8.1、基本使用
安装
pip install flask-sqlalchemy
若是安装失败,提示No module named 'MySQLdb',需要尝试下面方案
- pip install mysqlclient
- pip install pymysql
基本配置
配置项
| SQLALCHEMY_DATABASE_URI | 数据库连接地址 | 
|---|---|
| SQLALCHEMY_BINDS | 访问多个数据库时,用于设置数据库连接地址 | 
| SQLALCHEMY_ECHO | 是否打印底层执行的SQL | 
| SQLALCHEMY_RECORD_OUERIES | 是否记录执行的查询语句,用于慢查询分析,调试模式下自动启动 | 
| SQLALCHEMY_TRACK_MODIFICATIONS | 是否追踪数据库变化(触发钩子函数),会消耗额外的内存 | 
| SQLALCHEMY_ENGINE_OPTIONS | 设置针对sqlalchemy本体的配置项 | 
数据库URL
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:密码@127.0.0.1:3306/数据库名"
- 数据库驱动使用pymysql,协议名改为mysql+pymysql://root:密码@127.0.0.1:3306/数据库名
- sqlalchemy支持多种关系型数据库
2.8.2、数据操作
1)、add 新增
@app.route("/add")
def add_user():
    # 创建模型对象
    u1 = User(name="zhangsan", age=22)
    # u1.name = "lisi"
    # u1.age = 33
    # 模型对象添加到会话中
    db.session.add(u1)
    # 添加多条
    # db.session.add_all([u1,u2,u3])
    # 提交会话
    db.session.commit()
    # 手动回滚  默认自动回滚
    db.session.rollback()
    return "add ok"
2)、select 查询
常见的查询执行器
- all() 返回列表
- count() 返回查询结果数量
- first() 返回查询到的第一个模型对象,没有返回None
- first_or_404() 返回查询到的第一个模型对象,没有返回404
- get(主键) 返回主键对应的模型对象,不存在返回None
- get_or_404() 返回主键对应的模型对象,不存在返回404
- paginate(页码,每页条数) 返回paginate对象,包含分页查询的结果
    # 分页  每页3条,查询第二页数据
    p = User.query.paginate(2, 3)
    # p.page # 当前页数
    # p.pages  # 总页数
    # p.items # 数据
常见的查询过滤器
- filter_by(字段名=值)
 # 指定用户表
 User.query.filter_by(id=4).first()
- filter(函数引用/比较运算)
    # filter全局查询
    User.query.filter(User.id == 4).first()
    # 以什么结尾
    User.query.filter(User.name.endswith("san"))
    # 以什么开头
    User.query.filter(User.name.startswith("zhang"))
    # 内容包含什么
    User.query.filter(User.name.contains("zh"))
    # 模糊匹配 不推荐
    User.query.filter(User.name.like("z%s"))
    # 逻辑操作
    # 与操作1
    User.query.filter(User.name.startswith("zhang"), User.age == 33)
    # 与操作2
    from sqlalchemy import and_, or_, not_
    User.query.filter(and_(User.name.startswith("zhang"), User.age == 33))
    # 或操作
    User.query.filter(or_(User.name.startswith("zhang"), User.age == 33))
    # 非操作
    User.query.filter(not_(User.name == "zhangsan")).all()
    User.query.filter(User.name != "zhangsan").all()
    # in操作
    User.query.filter(User.id.in_([1, 3, 5, 7])).all()
- limit(限定条数)
- offset(偏移条数)
- order_by(排序字段)
    # 排序 并取前5个
    User.query.order_by(User.age, User.id.desc()).limit(5).all()
    # 排序,取2-5位4个数据
    User.query.order_by(User.age).offset(1).limit(4).all()
- group_by(分组字段)
- options() 针对原查询限定查询的字段
# 优化select * ,指定字段查询
from sqlalchemy.orm import load_only
User.query.options(load_only(User.name, User.age)).all()
返回的内容在模型中不存在,需要使用db.session.query
from sqlalchemy import func
# 各个年龄的个数
uu = db.session.query(User.age, func.count(User.name).label("count")).group_by(User.age).all()
# label 是取别名
3)、update 更新
- 先查询,再更新
u1 = User.query.filter(User.name == "zhangsan").first()
u1.name = "ZHANGSAN"
# db.session.add(u1) 默认可不加
db.session.commit()
- 基于过滤条件的更新
    User.query.filter(User.name == "ZHANGSAN").update({
        "age": 2222
    })
4)、delete 删除
- 先查询,再删除
u1 = User.query.filter(User.name == "zhangsan").first()
db.session.delete(u1)
db.session.commit()
- 基于过滤条件的删除
User.query.filter(User.name == "ZHANGSAN").delete()
db.session.commit()
5)、索引
建立索引增加了查询速度,降低了增删改的速度。
字段内容经常被增删改,不建议作为索引。
 
                    
                 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号