我正在查询表
Team
以获取所有团队的列表。该查询对象被输入到利用 sqlalchemy 的 paginate()
的分页函数。
该函数接受
order
和 order_by
的输入,确定结果查询的列和顺序。当直接对 Team
的一个属性执行排序时,这种方法效果很好,但我也想根据每个记录与另一个表 Player
的关系数执行排序。
使用
func.count()
、.join()
和 .group_by()
这是可能的 - 但是,如果球队没有任何球员记录,则查询中会忽略该记录。我想包含此查询中的所有结果。
我曾想过创建第二个查询,忽略第一个查询的结果,然后以某种方式将它们组合起来,然后将它们传递给分页函数,但我还没有找到一种方法来做到这一点。
有没有办法包含
count
应返回 0
的结果,或者是否有其他方法可以实现此效果?
功能:
def get_teams(filters):
"""Get the collection of all teams"""
page = filters['page']
per_page = filters['per_page']
order = filters['order'] # validates as either 'asc' or 'desc'
order_by = filters['order_by']
if order_by == 'active_players': # checks if sort needs to be done manually
query = db.session.query(Team, sa.func.count(PlayerTeam.id).label('count')) \
.join(Team.player_association) \
.filter(PlayerTeam.end_date == None) \
.group_by(Team) \
.order_by(getattr(sa, order)('count'))
else: # sort is directly on attribute, this is easy
query = sa.select(Team).order_by(getattr(sa, order)(getattr(Team, order_by)))
return Team.to_collection_dict(query, page, per_page)
型号:
class Team(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), index=True, unique=True, nullable=False)
# some other fields
player_association = db.relationship('PlayerTeam', back_populates='team',lazy='dynamic')
players = association_proxy('player_association', 'player')
@staticmethod
def to_collection_dict(query, page, per_page):
resources = db.paginate(query, page=page, per_page=per_page, error_out=False)
# convert resources to dict and return
class Player(db.Model):
id = db.Column(db.Integer, primary_key=True)
player_name = db.Column(db.String(64), nullable=False)
# some other fields
team_association = db.relationship('PlayerTeam', back_populates='player', lazy='dynamic')
teams = association_proxy('team_association', 'team')
class PlayerTeam(db.Model):
id = db.Column(db.Integer, primary_key=True)
player_id = db.Column(db.Integer, db.ForeignKey('player.id'))
team_id = db.Column(db.Integer, db.ForeignKey('team.id'))
end_date = db.Column(db.DateTime)
# some other fields
player = db.relationship('Player', back_populates='team_association')
team = db.relationship('Team', back_populates='player_association')
感谢使用 @snakecharmerb 的
.outerjoin
的建议,我找到了一个可行的解决方案。
单独使用外连接仍然会导致计数为 0 的行不被返回,但通过将附加过滤器移动到外连接的条件包括所有行。
修改查询:
query = db.session.query(Team, sa.func.count(PlayerTeam.id).label('count')) \
.outerjoin(PlayerTeam,
(Team.id == PlayerTeam.team_id) & (PlayerTeam.end_date.is_(None))
) \
.group_by(Team) \
.order_by(getattr(sa, order)('count'))```