如何用Flask SQLAlchemy查询多对多中间表的点赞统计(无冗余关联)
SQLAlchemy实现指定商品点赞数统计(避免不必要关联)
首先明确你的模型结构(基于Flask-SQLAlchemy):
from flask_sqlalchemy import SQLAlchemy import uuid db = SQLAlchemy() # 多对多中间表定义 customers_favorite_items = db.Table( 'customers_favorite_items', db.Column('customer_id', db.UUID, db.ForeignKey('customers.id'), primary_key=True), db.Column('item_id', db.UUID, db.ForeignKey('items.id'), primary_key=True) ) class Customer(db.Model): __tablename__ = 'customers' id = db.Column(db.UUID, primary_key=True, default=uuid.uuid4) # 其他业务字段... favorite_items = db.relationship( 'Item', secondary=customers_favorite_items, back_populates='favorited_by' ) class Item(db.Model): __tablename__ = 'items' id = db.Column(db.UUID, primary_key=True, default=uuid.uuid4) # 其他业务字段... favorited_by = db.relationship( 'Customer', secondary=customers_favorite_items, back_populates='favorite_items' )
核心实现思路
要避免不必要的关联,核心是直接操作中间统计数据,不加载Customer表的任何数据——因为你只需要点赞数,不需要客户的具体信息。以下是两种常用实现方式:
方式一:仅统计点赞数(直接查询中间表)
对应你提到的原生SQL逻辑,直接查询customers_favorite_items中间表,无需关联任何业务表:
from sqlalchemy import func def get_item_like_counts(item_uuids): # 直接从中间表聚合统计 count_results = db.session.query( customers_favorite_items.c.item_id, func.count(customers_favorite_items.c.customer_id).label('like_count') ).filter( customers_favorite_items.c.item_id.in_(item_uuids) ).group_by( customers_favorite_items.c.item_id ).all() # 转换为易读的字典结构 return {str(item_id): like_count for item_id, like_count in count_results}
方式二:统计+商品基础信息(仅关联Item表)
如果需要同时返回商品的其他字段(如名称、描述),只需关联Item表,依然不碰Customer表:
from sqlalchemy import func def get_items_with_like_counts(item_uuids): # 先子查询统计点赞数 like_count_subquery = db.session.query( customers_favorite_items.c.item_id, func.count(customers_favorite_items.c.customer_id).label('like_count') ).filter( customers_favorite_items.c.item_id.in_(item_uuids) ).group_by( customers_favorite_items.c.item_id ).subquery() # 关联Item表获取商品信息,用outerjoin保证无点赞的商品也能返回(点赞数为0) items_data = db.session.query( Item, like_count_subquery.c.like_count ).outerjoin( like_count_subquery, Item.id == like_count_subquery.c.item_id ).filter( Item.id.in_(item_uuids) ).all() return [ { 'item_id': str(item.id), 'item_name': item.name, # 替换为你的实际字段 'like_count': like_count or 0 } for item, like_count in items_data ]
为什么能避免不必要关联?
- 方式一完全绕过业务表,直接从中间统计表获取数据,没有任何join操作;
- 方式二仅关联
Item表获取必要信息,全程不涉及Customer表的关联或数据加载,避免了多余的查询开销。
内容的提问来源于stack exchange,提问作者ზურა კუპატაძე
相关产品推荐
相关产品推荐

