如何用Flask SQLAlchemy查询关联表并获取多对多关联模型字段?
嘿,我来帮你搞定这个多对多关联的问题!你的核心痛点是没法一次性拿到product_categories表的字段,还有对关系定义里的两次lazy参数有疑问,咱们一步步来解决:
1. 先修正多对多关系的定义
你现在的关系定义有点问题,导致关联的是中间表而不是ProductCategoryModel本身。咱们重新调整一下:
假设你的两个主模型是PlyPositionModel和ProductCategoryModel,在ProductCategoryModel里定义:
ply_positions = db.relationship( 'PlyPositionModel', secondary='product_category_ply_position', # 中间表名称 back_populates='product_categories', lazy='joined' # 这个参数让查询时直接JOIN加载关联数据 )
然后在PlyPositionModel里对应定义:
product_categories = db.relationship( 'ProductCategoryModel', secondary='product_category_ply_position', back_populates='ply_positions', lazy='joined' )
用back_populates代替backref能更清晰地双向绑定两个模型的关系,避免混淆。
2. 编写查询获取你要的字段
现在你有两种方式实现和原生SQL一样的效果:
方式一:直接查询模型并关联加载
这种方式会返回完整的模型对象,方便后续序列化:
# 一次性加载所有PlyPosition及其关联的ProductCategory positions = PlyPositionModel.query.options(db.joinedload(PlyPositionModel.product_categories)).all()
方式二:用select语句指定具体字段(和你的原生SQL对应)
如果你只想拿到指定字段,而不是整个模型对象,可以这么写:
from sqlalchemy import select stmt = select( PlyPositionModel.plyPositionId, PlyPositionModel.plyPositionName, PlyPositionModel.createdAt, PlyPositionModel.updatedAt, ProductCategoryModel.productCatName ).join(PlyPositionModel.product_categories) results = db.session.execute(stmt).all()
3. 序列化时包含关联字段(如果用Marshmallow)
如果你用Marshmallow做序列化,需要在Schema里嵌套关联模型的Schema:
class ProductCategorySchema(ma.SQLAlchemyAutoSchema): class Meta: model = ProductCategoryModel load_instance = True class PlyPositionSchema(ma.SQLAlchemyAutoSchema): # 嵌套ProductCategorySchema,many=True表示是多对多关系 product_categories = ma.Nested(ProductCategorySchema, many=True) class Meta: model = PlyPositionModel load_instance = True
这样序列化后的结果就会包含productCatName等product_categories表的字段了。
4. 关于两次lazy参数的疑问
你原来代码里的两次lazy=True:
ply_position = db.relationship('PlyPositionModel', secondary="product_category_ply_position", lazy=True, backref=db.backref('product_category', lazy=True))
- 第一个
lazy=True等价于lazy='select',意思是当你访问ProductCategoryModel.ply_position时,会在用到这个属性的时候才发起额外查询(延迟加载)。 backref里的lazy=True是给PlyPositionModel动态添加的product_category属性设置延迟加载。
但问题在于这个product_category属性关联的是中间表,不是ProductCategoryModel,所以才拿不到分类的字段。咱们调整后的关系定义里,lazy='joined'是让查询主模型时,通过JOIN语句一次性把关联数据查出来,正好满足你“一次查询获取所有字段”的需求。
最终效果示例
调整后,你得到的序列化结果应该类似这样:
[ { "plyPositionId": 2, "plyPositionName": "Flute", "createdAt": 1234, "updatedAt": null, "product_categories": [ { "productCatId": 1, "productCatName": "示例分类", "createdAt": "2024-05-20T10:00:00", "updatedAt": null } ] }, { "plyPositionId": 1, "plyPositionName": "Top", "createdAt": 123, "updatedAt": null, "product_categories": [ { "productCatId": 1, "productCatName": "示例分类", "createdAt": "2024-05-20T10:00:00", "updatedAt": null } ] } ]
这样就完美拿到你想要的所有字段啦!
内容的提问来源于stack exchange,提问作者Himadri Ganguly

