1.Python操作MySQL驱动
Flask想要操作数据库,必须先安装python操作MySQL驱动。在python中,目前有以下的MySQL驱动包(建议使用mysqlclient):
mysqlclient:是目前执行最快的驱动,通过pip install mysqlclient安装,而不要在PyCharm中直接安装,可能会报错。
PyMySQL:这是一个纯Python的MySQL客户端库,但执行效率不如mysqlclient。
mysql-connector-python:这是MySQL官方提供的Python连接驱动,纯Python实现,不需要MySQL客户端库。
注意:本博客内容的所有代码基于使用mysqlclient。
2.Flask-SQLAlchemy
在Flask中,很少直接使用驱动程序(mysqlclient)来直接写原生SQL语句去操作数据库,更多的是使用SQLAIchemy提供的ORM(Object Relationship Mapping),类似于操作普通的python对象一样去实现数据库的增删改查操作。而Flask-SQLAIchemy是对SQLAIchemy的一个封装,使得在Flask中使用SQLAIchemy更加方便。Flask-SQLAIchemy需要单独安装,因为Flask-SQLAIchemy依赖于SQLAIchemy,所以只需要安装Flask-SQLAIchemy,SQLAIchemy就会自动安装。(pip install flask-aqlalchemy)SQLAIchemy类似于Jinja2,可以独立Flask被使用,可以在任何python程序中被使用。
3.Flask-SQLAlchemy的使用
连接SQL
使用Flask-SQLAlchemy操作数据库之前,需要先创建一个Flask-SQLAlchemy提供的SQLAlchemy类的对象。在创建这个类时,需要传入当前的app,然后需要在app.config中设置SQLALCHEMY_DATABASE_URI,来配置数据库的连接。
from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text app = Flask(__name__) # MySQL所在的主机名 HOSTNAME = '127.0.0.1' # MySQL监听的端口号,默认3306 PORT=3306 # 连接MySQL的用户名 USERNAME="root" # 连接MySQL的密码,看自己的设置 PASSWORD="1234" # MySQL上创建的数据库名称 DATABASE="database_learn" # 如果驱动程序时mysqlclient,那么以下前缀就是:mysql+mysqldb # 如果驱动程序时pymysql,那么以下前缀就是:mysql+pymysql app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql://{USERNAME}:{PASSWORD}@{HOSTNAME}/{DATABASE}?charset=utf8mb4" app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True db = SQLAlchemy(app) # 测试是否连接成功的代码 with app.app_context(): with db.engine.connect() as conn: result=conn.execute(text("select 1")) print(result.fetchall()) @app.route('/') def hello_world(): # put application's code here return 'Hello World!' if __name__ == '__main__': app.run()
4.ORM模型
ORM介绍:面向对象技术映射,是一种可以使用python面向对象来操作关系型数据库的技术。具有可以映射到数据库能力的python类,称之为ORM模型。一个ORM模型与数据库中的一个表相对应,ORM模型中每一个类属性分别对应表的每个字段,ORM模型中的每一个实例对象对应表中每条数据。ORM技术提供了面向对象与SQL交互的桥梁。使用ORM模型 具有以下的优势:开发效率高、安全性高、灵活性强。
定义ORM模型,以下代码是使用Flask-SQLAlchemy来创建一个user模型。
from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text from sqlalchemy.orm import DeclarativeBase import config from sqlalchemy.orm import DeclarativeBase,Mapped,mapped_column from sqlalchemy import MetaData,Integer,String # 定义命名约定的Base类 class Base(DeclarativeBase): metadata = MetaData(naming_convention={ # ix:index,索引 "ix": "ix_%(column_0_label)s", # uq:unique,唯一约束 "uq": "uq_%(table_name)s_%(column_0_name)s", # ck:Check,检查约束 "ck": "ck_%(table_name)s_%(column_0_name)s", # fk:Foreign Key,外键约束 "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", # pk:Primary Key,主键约束 "pk": "pk_%(table_name)s" }) db = SQLAlchemy(app=app,model_class=Base) class User(db.Model): __tablename__ = 'user' id:Mapped[int]=mapped_column(Integer,primary_key=True,autoincrement=True) username:Mapped[str]=mapped_column(String(50),nullable=False) password:Mapped[str]=mapped_column(String(100),nullable=False) with app.app_context(): db.create_all()
在上述的代码中,字典naming_convention是一个固定的写法,主要是用来给表约束做一些命名约束的,使得后期alembic在生成迁移脚本时,生成的约束名不是随机的,而是有命名规范的。
在User模型中,使用Mapped[类型]语法来让开发者和IDE识别该属性的类别,为开发提供便捷性;另外,凡是使用mapped_column创建的属性都被映射都表中成为字段,并且该字段有什么配置,并且该字段有什么配置,都可以在mapped_column中添加相关参数。
之后,调用db.create_all()方法,就会将该模型迁移到数据库中生成一张表,这种方式在字段中发生改变时无法自动同步到数据库中,所以仅作为一种临时解决方案,后续会使用flask-migrate来实现。
常用的属性和参数
在上述user模型中,db.Integer和db.String,除了这两种模型,还有以下的模型:
| 字段类型 | 描述 | 对应MySQL类型 | 示例 |
|---|---|---|---|
| Integer | 整数类型 | INT | id = Column(Integer) |
| String | 字符串类型 | VARCHAR | name = Column(String(50)) |
| Text | 长文本类型 | TEXT | content = Column(Text) |
| Boolean | 布尔类型 | TINYINT(1) | is_active = Column(Boolean) |
| Float | 浮点数类型 | FLOAT | price = Column(Float) |
| Double | 双精度浮点数 | DOUBLE | rating = Column(Double) |
| Numeric/Decimal | 定点数 | DECIMAL | amount = Column(Numeric(10, 2)) |
| DateTime | 日期时间 | DATETIME | created_at = Column(DateTime) |
| Date | 日期 | DATE | birthday = Column(Date) |
| Time | 时间 | TIME | start_time = Column(Time) |
| Enum | 枚举类型 | ENUM | status = Column(Enum('active', 'inactive')) |
| JSON | JSON类型 | JSON | data = Column(JSON) |
| LargeBinary | 二进制数据 | BLOB | image = Column(LargeBinary) |
| PickleType | Python对象序列化 | BLOB | config = Column(PickleType) |
| 参数名 | 描述 | 默认值 | 示例 |
|---|---|---|---|
| primary_key | 设置为主键 | False | id = Column(Integer, primary_key=True) |
| autoincrement | 自增 | True(主键时) | id = Column(Integer, autoincrement=True) |
| nullable | 是否允许NULL | True | name = Column(String, nullable=False) |
| unique | 是否唯一 | False | email = Column(String, unique=True) |
| default | 默认值 | None | created_at = Column(DateTime, default=datetime.now) |
| server_default | 数据库端默认值 | None | status = Column(String, server_default='active') |
| onupdate | 更新时的值 | None | updated_at = Column(DateTime, onupdate=datetime.now) |
| index | 创建索引 | False | username = Column(String, index=True) |
| comment | 字段注释 | None | Column(String, comment='用户姓名') |
| name | 数据库列名 | 属性名 | Column('user_name', String(50)) |
| key | Python属性名 | None | Column('db_name', String, key='name') |
5.模型迁移
Flask-Migrate介绍
定义好模型后,是通过db.create_all()的形式将ORM模型映射到数据库中,这种形式比较局限,只能识别到新增了模型后映射到数据库中,对于模型中数据的修改、类型的修改无法识别。因此,在实际开发中,都不会使用db.create_all()来做ORM模型迁移,而是借助一个第三方库Flask-Migrate来实现。Flask-Migrate数据alembic来实现的,alembic是专门用来做SQLAlchemy的ORM模型做迁移的。要使用Flask-Migrate,先通过pip安装Flask-Migrate。
pip install flask-migrate==4.1.0,alembic会随着flask-migrate的安装而安装。
创建迁移对象
使用Flask-Migrate创建迁移对象,需要通过类Migrate来实现。
初始化迁移环境
在创建完迁移对象后,需要初始化一下迁移环境。方法是在当前的根目录下执行以下的命令:
flask db init
执行完命令后,会在根路径下生成一个migrations文件夹,该文件夹下有以下文件:
versions:文件夹,用于后面生成的迁移脚本文件。
alembic.ini:alembic的配置文件。
env.py:配合flask项目迁进行移的的python文件。
script.py.mako:生成迁移脚本的模板文件。
注意:次工作只需要初始化一遍,无需重复初始化。
生成迁移脚本
在初始化完成迁移环境的前提下,无论是新增ORM模型,还是ORM模型中有任何字段信息发生改变,并且想要将这些改变同步到数据库中,那么就需要进行修改,生成一个迁移脚本,生成迁移脚本命令如下:
flask db migrate -m "备注信息"
以上命令,-m后跟着的是备注信息,方便以后查看当前迁移脚本做了哪些事情。备注信息不是强制的,如果不想添加,可将-m及以后的命令删除。在执行完以上的命令后,version文件夹会新增一个python脚本文件。
执行迁移脚本
生成迁移脚本完成后,需要执行迁移脚本,才能把这些改变真正同步到数据库中。执行迁移脚本命令如下:
flask db upgrade
上述命令会自动从version文件夹中寻找最新的迁移脚本文件,然后执行迁移脚本文件中的upgrade函数,这步完成后,模型的修改就能真正的映射到数据库中。