模型 Django 方式的最后 'n' 外键微积分 (annotate/aggregate)?
Calculus on last 'n' ForeignKey of a Model Django way (annotate/aggregate)?
这是我的问题:我有两个模型:FieldPlayer(它代表具有不同值的运动会话,例如 report_id、得分、平均速度等)和 Player(可以执行多个会话的玩家,他有了名字、球队和联赛)。
以下是我的代码中的这些模型:
class FieldPlayer(models.Model):
"""
Represent the performance of a player on a game.
Has an owner and a remote report url.
"""
owner = models.ForeignKey(Player, related_name='performances')
report_id = models.IntegerField(null=True)
date = models.DateTimeField(default=timezone.now)
distance = models.FloatField(default=0)
pace = models.FloatField(default=0)
training_length = models.FloatField(default=0)
running_time_ratio = models.FloatField(default=0)
h_i_average_speed = models.FloatField(default=0)
h_i_run_time = models.FloatField(default=0)
explosivity = models.FloatField(default=0)
run_number = models.IntegerField(default=0)
overview = JSONField(null=True, blank=True) # Deprecated
game = models.ForeignKey(
Game, null=True, blank=True, related_name='players')
was_home = models.BooleanField(default=True)
speed_score = models.IntegerField(default=0)
stamina_score = models.IntegerField(default=0)
activity_score = models.IntegerField(default=0)
我的播放器模型:
class Player(models.Model):
name = models.CharField(max_length=50)
picture = ThumbnailerImageField(
upload_to='profile_pictures', resize_source={'size': (200, 200),
'crop': 'smart'}, blank=True, null=True)
team = models.ForeignKey(
Team, null=True, blank=True, related_name='players')
# TODO: Replace with db model instead of static string
league = {
"id": 1,
"name": "Champigny - Elite",
"logo": None
}
average_speed_score = models.IntegerField(default=0)
average_stamina_score = models.IntegerField(default=0)
average_activity_score = models.IntegerField(default=0)
score = models.IntegerField(default=0)
我需要获取以下值以显示我的 "Player-detail" 视图:
- 最近 5 场比赛的平均 speed_score 球员(比赛 = FieldPlayers 实例)
- 玩家最近 5 场比赛的平均水平 stamina_score。
- 玩家最近 5 场比赛的平均 activity_score。
- 得分值 = 以上所有 3 项得分的平均值。
- 最后 5 个会话的数组中的所有 'report_id' 值。
事实上,我已经能够以编程方式计算所有这些。例如,为了获得所有最近的 reports_ids 我在我的玩家模型中做了这些方法:
def get_n_last_sessions(self, n):
return self.performances.all()[:n]
def recents_reports(self):
sessions_list = self.get_n_last_sessions(5)
reports_ids = []
for sessions in sessions_list:
reports_ids.append(sessions.report_id)
return reports_ids
我可以为我需要的所有计算做同样的事情。但这是实现这一目标的好方法吗?我不这么认为,但如果我错了,请告诉我。
所以这才是真正的问题:如何用 Django annotate
或 aggregate
方式实现这种计算?这甚至可能 and/or 好的做法吗?
我完全不熟悉 Django 和 Python。
如果您正在寻找这些值作为模型的属性或函数,那么:
from django.db.models import Avg
class Player(models.Model):
....
....
@property
def average_speed_score(self):
return self.performances.order_by('-date')[:5].aggregate(Avg('speed_score'))
@property
def average_stamina_score(self):
return self.performances.order_by('-date')[:5].aggregate(Avg('stamina_score'))
@property
def average_activity_score(self):
return self.performances.order_by('-date')[:5].aggregate(Avg('activity_score'))
@property
def score(self):
return sum([self.average_speed_score, average_stamina_score, self.average_activity_score])/3
def return_last_n_report_ids(self, n):
return self.performances.objects.order_by('-date')[:n].values_list('report_id', flat=True)
您还可以了解 @property
装饰器 here, .aggregate
in the docs, and values_list
in the docs。
编辑:好的,根据评论中的说明更新:)
您可以在单个 (!) 数据库查询中轻松检索前四个要点中描述的信息。只需将查询集限制为 5 个元素 ([:5]
) 并执行适当的聚合:
from django.db.models import Avg
FieldPlayer.objects.filter(player=player).order_by('-date')[:5].aggregate(
avg_speed_score=Avg('speed_score'),
avg_stamina_score=Avg('stamina_score'),
avg_activity_score=Avg('activity_score'),
avg_all=(Avg('speed_score')+Avg('stamina_score')+Avg('activity_score'))/3,
)
player
是当前 Player
对象。
最后一点有点不同。这不是像上面那样的聚合,所以我认为你必须为此执行第二个查询:
FieldPlayer.objects.filter(player=player) \
.order_by('-pk')[:5].values_list('report_id', flat=True)
这将为您提供最近 5 个会话的所有 report_id
值的列表。
这是我的问题:我有两个模型:FieldPlayer(它代表具有不同值的运动会话,例如 report_id、得分、平均速度等)和 Player(可以执行多个会话的玩家,他有了名字、球队和联赛)。
以下是我的代码中的这些模型:
class FieldPlayer(models.Model):
"""
Represent the performance of a player on a game.
Has an owner and a remote report url.
"""
owner = models.ForeignKey(Player, related_name='performances')
report_id = models.IntegerField(null=True)
date = models.DateTimeField(default=timezone.now)
distance = models.FloatField(default=0)
pace = models.FloatField(default=0)
training_length = models.FloatField(default=0)
running_time_ratio = models.FloatField(default=0)
h_i_average_speed = models.FloatField(default=0)
h_i_run_time = models.FloatField(default=0)
explosivity = models.FloatField(default=0)
run_number = models.IntegerField(default=0)
overview = JSONField(null=True, blank=True) # Deprecated
game = models.ForeignKey(
Game, null=True, blank=True, related_name='players')
was_home = models.BooleanField(default=True)
speed_score = models.IntegerField(default=0)
stamina_score = models.IntegerField(default=0)
activity_score = models.IntegerField(default=0)
我的播放器模型:
class Player(models.Model):
name = models.CharField(max_length=50)
picture = ThumbnailerImageField(
upload_to='profile_pictures', resize_source={'size': (200, 200),
'crop': 'smart'}, blank=True, null=True)
team = models.ForeignKey(
Team, null=True, blank=True, related_name='players')
# TODO: Replace with db model instead of static string
league = {
"id": 1,
"name": "Champigny - Elite",
"logo": None
}
average_speed_score = models.IntegerField(default=0)
average_stamina_score = models.IntegerField(default=0)
average_activity_score = models.IntegerField(default=0)
score = models.IntegerField(default=0)
我需要获取以下值以显示我的 "Player-detail" 视图:
- 最近 5 场比赛的平均 speed_score 球员(比赛 = FieldPlayers 实例)
- 玩家最近 5 场比赛的平均水平 stamina_score。
- 玩家最近 5 场比赛的平均 activity_score。
- 得分值 = 以上所有 3 项得分的平均值。
- 最后 5 个会话的数组中的所有 'report_id' 值。
事实上,我已经能够以编程方式计算所有这些。例如,为了获得所有最近的 reports_ids 我在我的玩家模型中做了这些方法:
def get_n_last_sessions(self, n):
return self.performances.all()[:n]
def recents_reports(self):
sessions_list = self.get_n_last_sessions(5)
reports_ids = []
for sessions in sessions_list:
reports_ids.append(sessions.report_id)
return reports_ids
我可以为我需要的所有计算做同样的事情。但这是实现这一目标的好方法吗?我不这么认为,但如果我错了,请告诉我。
所以这才是真正的问题:如何用 Django annotate
或 aggregate
方式实现这种计算?这甚至可能 and/or 好的做法吗?
我完全不熟悉 Django 和 Python。
如果您正在寻找这些值作为模型的属性或函数,那么:
from django.db.models import Avg
class Player(models.Model):
....
....
@property
def average_speed_score(self):
return self.performances.order_by('-date')[:5].aggregate(Avg('speed_score'))
@property
def average_stamina_score(self):
return self.performances.order_by('-date')[:5].aggregate(Avg('stamina_score'))
@property
def average_activity_score(self):
return self.performances.order_by('-date')[:5].aggregate(Avg('activity_score'))
@property
def score(self):
return sum([self.average_speed_score, average_stamina_score, self.average_activity_score])/3
def return_last_n_report_ids(self, n):
return self.performances.objects.order_by('-date')[:n].values_list('report_id', flat=True)
您还可以了解 @property
装饰器 here, .aggregate
in the docs, and values_list
in the docs。
编辑:好的,根据评论中的说明更新:)
您可以在单个 (!) 数据库查询中轻松检索前四个要点中描述的信息。只需将查询集限制为 5 个元素 ([:5]
) 并执行适当的聚合:
from django.db.models import Avg
FieldPlayer.objects.filter(player=player).order_by('-date')[:5].aggregate(
avg_speed_score=Avg('speed_score'),
avg_stamina_score=Avg('stamina_score'),
avg_activity_score=Avg('activity_score'),
avg_all=(Avg('speed_score')+Avg('stamina_score')+Avg('activity_score'))/3,
)
player
是当前 Player
对象。
最后一点有点不同。这不是像上面那样的聚合,所以我认为你必须为此执行第二个查询:
FieldPlayer.objects.filter(player=player) \
.order_by('-pk')[:5].values_list('report_id', flat=True)
这将为您提供最近 5 个会话的所有 report_id
值的列表。