我试图创建一个Flask应用程序(Postgresql数据库),显示各个玩家的最新得分,包括团队的平均得分和目标。因此,玩家可以拥有多个分数,但在排行榜上我只想显示她最近的分数,并根据每位玩家的最新分数显示整个团队的平均目标数。
我的Models.py
class Player(db.Model):
__tablename__ = 'player'
id = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String, nullable=False)
score = db.relationship('Score', backref='player', lazy='dynamic')
def __init__(self, firstname):
self.firstname = firstname
def __repr__(self):
return '<id {}>'.format(self.id)
class Score(db.Model):
__tablename__ = 'score'
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, nullable=False)
score = db.Column(db.Integer, nullable=True)
goals = db.Column(db.Integer, nullable=True)
player_id = db.Column(db.Integer, db.ForeignKey('player.id'))
def __init__(self, score, player_id):
self.timestamp = datetime.now()
self.score = score
self.player_id = player_id
def __repr__(self):
return '<id {}>'.format(self.id)
我的app.py:
@app.route('/', methods=['GET', 'POST'])
@login_required
def home():
#Latest score per player
latest_scores_per_player = db.session.query(Player, Score).\
join(Score).\
distinct(Player.id).\
filter(Player.user_id == current_user.id).\
order_by(Player.id, Score.timestamp.desc())
#Average goals per player
avarage_goals = db.session.query(Player, Score).\
join(Score).\
distinct(Player.id).\
filter(Player.user_id == current_user.id).\
order_by(Player.id, Score.timestamp.desc()).\
func.avg(Score.goals).label('average').scalar()
return render_template(
'home.html',
latest_scores_per_player=latest_scores_per_player,
avarage_goals=avarage_goals)
&#39;每位玩家的最新得分&#39;正确显示每位玩家最新输入的分数。但是&#39;每位玩家的平均目标&#39;返回错误:
AttributeError:&#39; BaseQuery&#39;对象没有属性&#39; func&#39;
如何仅针对每位玩家最新输入的分数查询所有玩家的平均目标?
更新 我觉得我离得更近了:
#Average goals per player
avarage_goals = db.session.query(Player, Score, func.avg(Score.goals)).\
join(Score).\
distinct(Player.id).\
filter(Player.user_id == current_user.id).\
order_by(Player.id, Score.timestamp.desc()).scalar()
但还没到。努力让func.avg与distinct和order_by一起工作。
答案 0 :(得分:1)
如果我理解正确,那么您只需要将每位玩家的最新分数用作子查询并对结果取平均值。由于您以每个玩家的最新分数存储Query对象,因此您可以使用:
@app.route('/', methods=['GET', 'POST'])
@login_required
def home():
# Latest score per player
latest_scores_per_player = db.session.query(Player, Score).\
join(Score).\
distinct(Player.id).\
filter(Player.user_id == current_user.id).\
order_by(Player.id, Score.timestamp.desc())
# Create a subquery that queries only the goals from the groups
subq = latest_scores_per_player.\
with_entities(Score.goals).\
subquery()
#Average goals *across all players*
average_goals = db.session.query(func.avg(subq.c.goals)).scalar()
return render_template(
'home.html',
latest_scores_per_player=latest_scores_per_player,
avarage_goals=average_goals)
这将进行两次数据库访问。您也可以只查询每个玩家的最新得分结果并计算Python中的平均值。使用最新版本的Python,您可以使用statistics模块:
import statistics
@app.route('/', methods=['GET', 'POST'])
@login_required
def home():
# Latest score per player
# Materialize the results to a list here for calculating average
latest_scores_per_player = db.session.query(Player, Score).\
join(Score).\
distinct(Player.id).\
filter(Player.user_id == current_user.id).\
order_by(Player.id, Score.timestamp.desc()).\
all()
average_goals = None
if latest_scores_per_player:
average_goals = statistics.mean(
score.goals for player, score in latest_scores_per_player)
return render_template(
'home.html',
latest_scores_per_player=latest_scores_per_player,
avarage_goals=average_goals)
或者自己动手(如果使用Python 2,则添加必要的转换以浮动):
average_goals = None
if latest_scores_per_player:
average_goals = sum(
score.goals for player, score in latest_scores_per_player)
average_goals /= len(latest_scores_per_player)