2

這是我的問題:我有兩個模型:FieldPlayer(它代表一個體育會議,具有不同的值,如report_id,分數,平均速度等)和球員(可以執行多次球員的球員,他有一個名字,一個團隊和一個聯盟)。模型Django方式的最後'n'ForeignKey上的微積分(註釋/聚合)?

下面是我的代碼論文型號:

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) 

我需要得到下面的值,以顯示我的「播放器細節」的觀點:

  • 最近5場比賽的球員平均speed_score(會話= FieldPlayers實例)
  • 最近5場比賽的球員的平均耐力得分。
  • Player最近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 annotateaggregate的方式實現這種計算?這甚至可能和/或良好做法?

我完全不熟悉Django和Python。

+0

如果speed_score記錄在Player模型中,而不是FieldPlayer模型中,你希望如何得到最後5場比賽的球員的平均speed_score? –

+0

這是一個複製/粘貼錯誤,實際上都有得分屬性。編輯 – Addict

回答

2

如果您正在尋找那麼這些值屬性或功能上的模型:

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.aggregatedocs,並values_listdocs爲好。

編輯:(!)好吧,在評論:)

+0

我很抱歉混淆我剛更新了我的問題。 'speed_score','stamina_score'和'activity_score'實際上存儲在FieldPlayer Model中。 作爲例子的'average_speed_score'必須是最後5個FieldPlayers'speed_score'的平均值(Player可以與許多FieldPlayer相關,參見ForeignKey)。 但我還需要一個與最後5個FieldPlayers對應的'report_id'列表。 – Addict

+0

啊,我明白了,我更新了我的答案,添加了一個函數,返回報告ID – ben432rew

+0

您的答案和Ludwik的答案都很好。謝謝 ! – Addict

1

您可以輕鬆檢索您點的前四個在一個單一的數據庫查詢說明信息來自澄清更新。只是限制查詢集到5個元素([:5])並執行approperiate聚合:

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) 

這將讓你所有的report_id值的列表最後5次。

+0

感謝您回答這個問題,這似乎正是我要找的。 我在哪裏放置FieldPlayer.objects.filter?在我的ViewSet/Serializer上?最佳做法是什麼? – Addict

+1

如果您認爲您可能希望重複使用其他視圖中的信息,則可以將其放入您的ViewSet中或在「Player」對象上創建一個方法。 –