数据库配置文件(config.py
)
# config.py
USERNAME = "root" # 数据库登录用户名
PASSWORD = "123456" # 数据库登录密码
HOST = "localhost" # 数据库服务器地址,若为远程服务器填写对应的IP地址,这里是示例地址
PORT = "3306" # 数据库连接端口号,MySQL默认常用端口是3306
DATABASE = "test_platform" # 要访问的数据库名称
# 创建统一资源标识符(URI),用于指定数据库连接的详细信息
# SQLALCHEMY_DATABASE_URI的格式为:数据库类型 + 驱动://{登录名}:{密码}@{IP地址}:{端口号}/{数据库名}?charset={编码格式}
DB_URI = f'mysql+pymysql://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/{DATABASE}?charset=utf8'
# SQLALCHEMY_DATABASE_URI配置项,设置数据库的连接URI,让SQLAlchemy知道如何连接数据库
SQLALCHEMY_DATABASE_URI = DB_URI
# SQLALCHEMY_TRACK_MODIFICATIONS配置项,用于控制是否动态追踪对象修改情况
# 若设置为True,会追踪对象修改,但会消耗额外资源,默认不设置时会有告警提示,这里设为True开启追踪
SQLALCHEMY_TRACK_MODIFICATIONS = True
# SQLALCHEMY_ECHO配置项,用于设置是否在查询时显示原始的SQL语句
# 设为False表示不显示原始SQL语句,设为True则会在控制台等地方输出实际执行的SQL语句,方便调试查看
SQLALCHEMY_ECHO = False
Flask应用与SQLAlchemy初始化
创建Flask应用实例
在主应用文件(例如 app.py
)中创建Flask应用实例,代码如下:
from flask import Flask
app = Flask(__name__)
导入配置数据
使用 app.config.from_pyfile()
方法从配置文件(config.py
)导入配置信息到Flask应用实例中,示例代码:
from config import Config
app.config.from_pyfile(Config)
创建SQLAlchemy实例并关联应用(init_app
相关解释)
init_app
用法示例:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
return app
- 为什么要用
init_app
:
在实际项目开发场景中,应用往往需要在不同的环境(如开发环境、测试环境、生产环境)下运行,而不同环境下的数据库配置通常是不一样的。
例如,开发环境下可能使用一个本地搭建的测试数据库,用户名、密码以及数据库名称等信息都是针对开发调试设置的;测试环境会使用专门的测试服务器上的数据库,有着独立的一套访问配置;生产环境更是有严格的线上数据库配置,涉及安全、性能等多方面考量。
通过 init_app
方法,我们可以先独立创建 SQLAlchemy
实例,之后根据具体的Flask应用在不同环境下的配置情况,再将二者关联起来。这样的方式使得数据库配置能够灵活切换,避免了把数据库配置固定写死在代码之中,极大地增强了代码的可维护性与扩展性,方便应对复杂多变的项目需求。
- 可以不用
init_app
吗:
是可以的。如果项目相对简单,数据库配置固定不变,不存在要根据不同环境切换配置的情况,那么直接在创建 SQLAlchemy
实例时传入Flask应用实例进行初始化就可以了,如下所示:
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
app = Flask(__name__)
# 直接通过app.config来配置SQLAlchemy相关的参数
app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:///example.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 直接传入app实例初始化,适合简单且配置固定的应用场景
db = SQLAlchemy(app)
不过对于大型、复杂的项目,尤其是那些需要频繁在不同环境间切换配置的项目,使用 init_app
会更加合适、便捷。
创建和删除表
创建表
在启动脚本(比如在 if __name__ == '__main__':
部分)按照以下方式创建表结构,这里涉及到 with app.app_context()
的使用:
if __name__ == '__main__':
from app import app, db
with app.app_context():
db.create_all()
app.run()
关于 with app.app_context()
的解释:
Flask应用在运行时依赖应用上下文(app context
)来管理和应用相关的各种状态以及配置信息。当执行 db.create_all()
操作时,它需要依据当前应用配置里通过 SQLALCHEMY_DATABASE_URI
配置项指定的数据库连接详情,再结合代码中定义的数据库模型类等相关信息,才能准确无误地在数据库中创建对应的表结构。
只有在这个应用上下文环境里,SQLAlchemy
才能获取到正确的配置信息,要是没有这个环境,比如直接从外部脚本运行相关代码时,SQLAlchemy
很可能无法获取到准确的配置内容,进而导致创建表的操作失败。
删除表
当需要删除表(注意,删除表操作会清除对应表中的所有数据,操作时要格外谨慎)时,同样需要在合适的脚本中使用 with app.app_context()
,示例如下:
if __name__ == '__main__':
from app import app, db
with app.app_context():
db.drop_all()
app.run()
使用 with app.app_context()
的原因和创建表时一样,都是为了确保 db.drop_all()
操作能够依据当前Flask应用的配置准确地对数据库中的表进行删除操作,避免因获取不到正确配置而出现错误。
查询操作
查询所有记录
db
语句:
results = db.session.query(YourModel).all()
sql
语句:
SELECT * FROM your_table_name;
查询指定列记录
db
语句:
results = db.session.query(YourModel.column1, YourModel.column2).all()
sql
语句:
SELECT column1, column2 FROM your_table_name;
条件查询记录
db
语句:
results = db.session.query(YourModel).filter(YourModel.column_name > value).all()
sql
语句:
SELECT * FROM your_table_name WHERE column_name > value;
模糊查询记录(使用 LIKE
)
db
语句:
results = db.session.query(YourModel).filter(YourModel.column_name.like('%keyword%')).all()
sql
语句:
SELECT * FROM your_table_name WHERE column_name LIKE '%keyword%';
范围查询记录
- 使用
BETWEEN... AND...
db
语句:
results = db.session.query(YourModel).filter(YourModel.column_name.between(start_value, end_value)).all()
- **`sql` 语句**:
SELECT * FROM your_table_name WHERE column_name BETWEEN start_value AND end_value;
- 使用
IN
db
语句:
results = db.session.query(YourModel).filter(YourModel.column_name.in_(list_of_values)).all()
- **`sql` 语句**:
SELECT * FROM your_table_name WHERE column_name IN (value1, value2,...);
排序查询记录(使用 ORDER BY
)
db
语句:
results = db.session.query(YourModel).order_by(YourModel.column_name.desc()).all()
sql
语句:
SELECT * FROM your_table_name ORDER BY column_name DESC;
分组查询记录(使用 GROUP BY
和 HAVING
)
db
语句:
from sqlalchemy import func
results = db.session.query(YourModel.column_group, func.count(YourModel.id)).group_by(YourModel.column_group).having(func.count(YourModel.id) > some_value).all()
sql
语句:
SELECT column_group, COUNT(id) FROM your_table_name GROUP BY column_group HAVING COUNT(id) > some_value;
多表关联查询记录(以简单的内连接为例)
假设有 ModelA
和 ModelB
两个模型类,通过 ModelA.id
和 ModelB.a_id
关联:
db
语句:
results = db.session.query(ModelA.column1, ModelB.column2).join(ModelB).all()
sql
语句:
SELECT ModelA.column1, ModelB.column2 FROM ModelA JOIN ModelB ON ModelA.id = ModelB.a_id;
子查询记录
db
语句:
from sqlalchemy import select
subquery = db.session.query(func.avg(YourModel.column_name)).scalar_subquery()
results = db.session.query(YourModel).filter(YourModel.column_name > subquery).all()
sql
语句:
SELECT * FROM your_table_name WHERE column_name > (SELECT AVG(column_name) FROM your_table_name);
去重查询记录(使用 DISTINCT
)
db
语句:
results = db.session.query(YourModel.column_name).distinct().all()
sql
语句:
SELECT DISTINCT column_name FROM your_table_name;
分页查询记录
db
语句:
# limit 用于指定每页显示的记录数量,offset 用于设置偏移量,也就是从哪条记录开始查询
results = db.session.query(YourModel).limit(page_size).offset(page_number * page_size).all()
# paginate:进行分页操作,page参数指定页码,per_page参数指定每页显示的记录数。
results = db.session.query.paginate(page=page_number, per_page=page_size).all()
sql
语句:
SELECT * FROM your_table_name LIMIT offset_value, page_size;
插入操作
插入单条记录
db
语句:
new_record = YourModel(column1=value1, column2=value2)
db.session.add(new_record)
db.session.commit()
sql
语句:
INSERT INTO your_table_name (column1, column2) VALUES (value1, value2);
插入多条记录
db
语句:
records_to_add = [
YourModel(column1=value1_1, column2=value2_1),
YourModel(column1=value1_2, column2=value2_2)
]
db.session.add_all(records_to_add)
db.session.commit()
sql
语句:
INSERT INTO your_table_name (column1, column2) VALUES (value1_1, value2_1), (value1_2, value2_2);
更新操作
更新单条记录
db
语句:
record = db.session.query(YourModel).filter(YourModel.id == record_id).first()
if record:
record.column_name = new_value
db.session.commit()
sql
语句:
UPDATE your_table_name SET column_name = new_value WHERE id = record_id;
更新多条记录(基于条件)
db
语句:
db.session.query(YourModel).filter(YourModel.column_name == condition_value).update({YourModel.column_to_update: new_value})
db.session.commit()
sql
语句:
UPDATE your_table_name SET column_to_update = new_value WHERE column_name = condition_value;
删除操作
删除单条记录
db
语句:
record = db.session.query(YourModel).filter(YourModel.id == record_id).first()
if record:
db.session.delete(record)
db.session.commit()
sql
语句:
DELETE FROM your_table_name WHERE id = record_id;
删除多条记录(基于条件)
db
语句:
db.session.query(YourModel).filter(YourModel.column_name == condition_value).delete()
db.session.commit()
sql
语句:
DELETE FROM your_table_name WHERE column_name = condition_value;