• flask-sqlalchemy库


    彩笔激流勇退。

    1. 简介

    ORM,对象关系映射。简单来说,ORM将数据库中的表与面向对象中的类建立了一种对应关系。这样,我们要操作数据库,表,记录就可以直接通过操作类或者类实例来完成。

    SQLAlchemy 是目前python中最垃圾的 ORM框架, 功能全面, 使用复杂。

    Flask-SQLAlchemy 是一个为 Flask 应用增加 SQLAlchemy 支持的扩展,把原本pymysql几句话就能搞定的事情整成抽象的,继承的,封装的,多态的更适合高级程序员体质的负离子保温杯。

    抛开兼容性不谈,Flask-SQLAlchemy无疑是磨练程序员改bug的磨刀石,是检验程序员记忆能力的试金石,是凝结了人类精华的草酸钙结石。

    常用字段类型

    类型名python接收类型mysql生成类型说明
    Integerintint整型
    Floatfloatfloat浮点型
    Numeric(5,2)decimal.Decimaldecimal(5,2)
    Booleanbooltinyint整型,只占1个字节
    Textstrtext文本类型,最大64KB
    LongTextstrlongtext文本类型,最大4GB
    Stringstrvarchar变长字符串,必须限定长度
    Datedatetime.datedate日期
    DateTimedatetime.datetimedatetime日期和时间
    Timedatetime.timetime时间
    TIMESTAMPdatetime.datetimeTIMESTAMP时间戳,可以用text(‘now()’)赋值

    常用的字段选项

    选项名说明
    primary_keyTrue,则该字段为表的主键,默认自增
    uniqueTrue,则这列设置唯一
    nullableFalse,则这列设置非空
    default为这列设置默认值,不作用在数据库
    server_default值必须是字符串格式,作用在数据库
    indexTrue,则为这列创建索引,提高查询效率

    如果没有给对应字段的类属性设置default参数, 且添加数据时也没有给该字段赋值, 则sqlalchemy会给该字段设置默认值 None。

    常见命令

    db.create_all() #创建所有表
    db.drop_all() #删除所有表
    
    • 1
    • 2
    2. 创建表

    pip install pymysql

    pip install flask-sqlalchemy

    数据库URL(连接地址)格式: 协议名://用户名:密码@数据库IP:端口号/数据库名

    main.py

    ​ 在下面代码中,我们使用了 with app.app_context(): 语句来确保当前应用实例的操作db.create_all() 是在flask应用上下文中被调用的。

    from app import *
    from models import User
    
    @app.route('/',methods=['GET','POST'])
    def login():
        print(db)
        return 'hello world'
    
    if __name__ == '__main__':
        with app.app_context():
            db.create_all()#创建表
        app.run(host='0.0.0.0',port=9901,debug=1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    modules.py

    表名默认为类名小写, 可以通过 __tablename__类属性 进行修改

    from app import db
    
    class User(db.Model):# User表
        __tablename__ = 't_user'
        id= db.Column(db.Integer,primary_key=True) # 必须要有主键存在
        name=db.Column(db.String(20),nullable=True)# 可空
        age=db.Column(db.SmallInteger)
        gender=db.Column(db.Boolean)
        birthday=db.Column(db.Date)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    对应MySQL语句

    CREATE TABLE `t_user` (
      `id` int NOT NULL AUTO_INCREMENT,
      `name` varchar(20) COLLATE utf8mb4_general_ci DEFAULT NULL,
      `age` smallint DEFAULT NULL,
      `gender` tinyint(1) DEFAULT NULL,
      `birthday` date DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    app.py

    from flask import Flask,url_for,request,render_template,make_response,redirect,jsonify
    from flask_sqlalchemy import SQLAlchemy
    app = Flask(__name__) # 用本脚本名实例化Flask对象
    # 设置数据库连接地址
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@127.0.0.1:3306/test1'
    
    # 是否追踪数据库修改(开启后会触发一些钩子函数)  一般不开启, 会影响性能
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    
    # 是否显示底层执行的SQL语句
    app.config['SQLALCHEMY_ECHO'] = True
    
    # 初始化组件对象, 直接关联Flask应用
    db = SQLAlchemy(app)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    3. 数据表简单查询

    在这里插入图片描述

    user=User.query

    说明
    user.filter_by(id=1)只能等值查询,使用=
    user.filter(User.id==1)条件查询,用==
    use.filter 参数与运算符说明
    and_(User.id==1,User.age==99)
    or_(User.id==1,User.age==99)
    ~(User.id==1)
    != None>>=
    User.name.like('%a%')模糊查询
    User.id.in_((1,2,5))范围查询
    User.id.between(1,3)[1,3]
    if __name__ == '__main__':
        with app.app_context():
            db.create_all()
            user=User.query
            print(user)#显示sql语句, 返回Query对象
            print(user.all())#[, , ],每个元素都是models.User类型
            print(user.count()) #返回query中的Model对象数量
            print(user.filter_by(age=30,id=1)) #显示SQL语句, 返回Query对象,内部条件为交集
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    4. 映射查询 db.session.query

    映射查询在SQLAlchemy中,可以通过session对象的query方法完成。

    注意关键字书写顺序

    db.session.query().filter().group_by().having().order_by().paginate().all()
    
    • 1
    if __name__ == '__main__':
        with app.app_context():
            db.create_all()
            query=db.session.query(User) #
            print(query.filter(User.id>1).all())# [, ]
            query2=db.session.query(User.id,User.name)
            print(query2.filter(User.age==99).all())# [(2, 'tom')]
        app.run(host='0.0.0.0',port=9901,debug=1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    5. 排序 order_by

    from sqlalchemy import desc

    if __name__ == '__main__':
        with app.app_context():
            db.create_all()
            query = db.session.query(User.id, User.name,User.age)
            print(query.order_by(User.age).all())  # 默认升序排序,asc()
            print(query.order_by(desc(User.age)).all())  # 降序排序
            print(query.order_by(User.age,User.id).all())  # 先排age,后排id
        app.run(host='0.0.0.0', port=9901, debug=1)# 看起来是一个阻塞函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    6. 聚合函数

    数据库先添加一个age为30的记录。

    from sqlalchemy import func

    聚合函数说明
    count()记录数量
    sum()加和总值
    avg()平均值
    max()最大值
    min()最小值
    if __name__ == '__main__':
        with app.app_context():
            db.create_all()
            query = db.session.query(func.max(User.age),func.avg(User.age))
                #相当于 SELECT max(age) , avg(age) FROM t_user
            print(query.all())  # [(99, Decimal('51.0000'))]
        app.run(host='0.0.0.0', port=9901, debug=1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    7. 分组查询 group_by
    if __name__ == '__main__':
        with app.app_context():
            db.create_all()
            query = db.session.query(func.count(User.id))
            print(query.group_by(User.age).all())  
            # [(2,), (1,), (1,)]
        app.run(host='0.0.0.0', port=9901, debug=1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    8. 增删改

    flask开了debug模式,删除数据会导致main函数重新执行,给爷整笑了。

    if __name__ == '__main__':
        with app.app_context():
            db.create_all()
    
            #更新
            u = db.session.query(User.id==1)# 查询主键为1的记录
            u.name="Jack"
            #db.session.rollback() 事务回滚,默认遇到错误自动回滚
            db.session.commit()# 事务提交
    
            #删除
            u2=db.session.query(User).filter(User.id==6).all() # User 模型的实例
            if len(u2)!=0:
                db.session.delete(u2[0])
                db.session.commit()  # 事务提交
    
            #增加
            u3=User(id=7,name="lihua",age=35,gender=1,birthday='2077-1-1')
            db.session.add(u3)
            #db.session.add_all([u1,u2,u3]) 一次添加多个
            db.session.commit()
    
        app.run(host='0.0.0.0', port=9901, debug=0)
        # debug=1时,上面的delete操作会执行多次
        # 大概是是检测到了文件变化重启了一次main函数???
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    9. 分页查询 paginate

    分页查询不老老实实用limit,非要整个paginate装什么高大上。

    if __name__ == '__main__':
        with app.app_context():
            db.create_all()
            pg=db.session.query(User).paginate(page=2,per_page=2)# QueryPagination object
            print(pg.items)#[, ],当前页数据
            print(pg.pages) #3 ,一共三页
            for i in pg.iter_pages(): #迭代Pagination.iter_pages对象
                print(i)#1 2 3
        app.run(host='0.0.0.0', port=9901, debug=0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    10. 原生sql支持
    if __name__ == '__main__':
        with app.app_context():
            db.create_all()
            statement=text('select * from t_user where id> :id').params(id=1)
            query=db.session.query(User).from_statement(statement)
            print(query.all())# [, , , ]
    
            #最傻逼的地方来了,新版本下面语句不支持
            # statement2 = text('select max(id) as mmid,max(age) as mage from t_user where id> :id').params(id=2)
            # query2 = db.session.query('mmid','mage').from_statement(statement2)# sqlalchemy.exc.ArgumentError
    
            # 感觉不如直接pymysql
            sql=text('select max(id) as mmid,max(age) as mage from t_user where id> :id')
            result=db.session.execute(sql,{'id':2})# CursorResult object
            #print(result.fetchall())# [(7, 45)] 如果这里获取了,下面就获取不了,有点类似游标后移导致没数据读
            for i in result:
                print(i)# (7, 45)
        app.run(host='0.0.0.0', port=9901, debug=0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    参考

    flask框架与mysql开发入门到实践 白菜爱科技

  • 相关阅读:
    Perl 中的模式匹配修饰符
    【看表情包学Linux】软件包管理器 yum | Vim 编辑器介绍 | Vim 文本批量化操作
    allure测试报告生成逻辑--解决在Jenkins里打开allure报告页面后空白显示无数据问题(以window环境为例)
    5.32 综合案例2.0 - TTS语音云播报(支持M320开发板)
    C语言 每日一题 牛客网 11.12 Day16
    (附源码)springboot流浪动物救助系统 毕业设计 180920
    【算法|双指针系列No.3】leetcode202. 快乐数
    MySQL小知识:为何从8.0开始取消了MySQL查询缓存
    混合云运维解决方案,支持公有云、私有云、信创云等环境
    Spring Boot + vue-element 开发个人博客项目实战教程(二十四、文章管理页面开发(3))
  • 原文地址:https://blog.csdn.net/google20/article/details/136584205