最近做项目中想到了这个问题,原因是我想要直接往一个存放多对多关系的中间表导入数据,发现定义表时使用的是用db.Table定义,而非db.Model。 从而无法通过新建对象,然后调用db.Model.add方法进行数据插入,也无法通过db.Model.Query进行查询(Query方法来源于flask-sqlalchemy,非sqlalchemy)。从而对这个问题进行了一些研究思考。
在 SQLAlchemy 中,当你需要直接定义一个中间表或者操作一个并非基于 ORM 类(即非 db.Model
子类)的现有数据库表时,通常会使用 Table
对象而非 Model
。这是因为 db.Model
是用于构建对象关系映射(ORM)模型的基础类,它更适合用于那些我们希望以面向对象的方式进行操作的实体表,这些实体表有对应的 Python 类,并通过 SQLAlchemy 的声明式方式映射到数据库表。
而 Table
主要是用来定义或引用数据库表结构的底层组件,它主要用于不依赖 ORM 层或者说不需要实体类的对象关系描述。以下几种场景中经常使用 Table
:
- 多对多关系(Many-to-Many Relationships) : 在 SQLAlchemy 中建立多对多关系时,通常会有一个中间关联表,这个表往往仅用于存储两个其他表之间的关联关系,而不包含额外的行为或属性。这种情况下,我们不会为此创建一个完整的 ORM Model,而是直接定义一个
Table
来描述这个关联表结构。
python
association_table = Table('association', Base.metadata,
Column('left_id', Integer, ForeignKey('left_table.id')),
Column('right_id', Integer, ForeignKey('right_table.id'))
)
class Left(BaseORM):
# ...
right = relationship("Right", secondary=association_table)
class Right(BaseORM):
# ...
left = relationship("Left", secondary=association_table)
- 现有表无 ORM 映射: 如果你需要操作一个已经在数据库中存在的表,但并不打算为其创建一个完整的 ORM Model,那么你可以用
Table
来定义这个表结构以便进行 CRUD 操作。
python
existing_table = Table('existing_table', Base.metadata,
autoload_with=engine) # 使用引擎自动加载已有表结构
- 原生 SQL 查询: 当你只打算执行一些原生 SQL 查询而不涉及 ORM 实体时,可以直接使用
Table
和 SQLAlchemy Core API 来构造查询。
table.insert().values(loads)
总之,在 SQLAlchemy 中,Model
和 Table
各有其适用场景。当需要更精细地控制表结构,或者处理不需完整 ORM 映射的情况时,Table
是更为合适的选择。而对于业务实体,通常建议使用 Model
进行映射,从而利用 ORM 提供的便利性。
实际使用中,感觉不如一开始定义表时使用db.Model更方便。
当我用db.Table定义时,我需要这样构建语句来进行插入
def schema2dbbyORM(filepath, SchemaName):
with open(filepath, 'r', encoding='utf-8') as file:
data = json.load(file)
# schema = SchemaName(many=True)
try:
loads = SchemaName(load_instance=False, many=True).load(data)
except ValidationError as err:
pprint(err.messages)
# loads 为字典, 需要用到对应到db.Table对象来构建语句
stmt = dict_Schema2ORMOrTable.get(SchemaName.__name__).insert().values(loads)
result = db.session.execute(stmt)
print(f'{SchemaName.__name__} Inserted {result.rowcount} rows')
db.session.flush()
db.session.commit()
当使用db.Model时
def schema2db(filepath, SchemaName):
with open(filepath, 'r', encoding='utf-8') as file:
data = json.load(file)
# schema = SchemaName(many=True)
try:
loads = SchemaName(many=True).load(data)
except ValidationError as err:
pprint(err.messages)
# loads 为Model实体
print(f'{SchemaName.__name__} Inserted {len(loads)} rows')
db.session.add_all(loads)
db.session.commit()
如上,实际使用中,感觉不如一开始定义表时使用db.Model更方便。