2017-02-24 58 views
-1

我有我用約一個團隊如何在體育聯盟進行顯示細節串行..如何在SerializerMethodFields之間共享查詢集?

class TeamLeagueSerializer(ModelSerializer): 
    class Meta: 
     model = Team 
     fields = [...] 
    games_played = fields.SerializerMethodField() 
    games_won = fields.SerializerMethodField() 
    games_lost = fields.SerializerMethodField() 
    points_for = fields.SerializerMethodField() 
    ...etc... 

    def fixtures(self, team): 
     # Retrieves all relevant fixtures for a given season and a given team 
     return Fixture.objects.filter(Q(home_team=team) | Q(away_team=team), season=self.season) 

    def get_games_won(self, obj): 
     home_results = Q(home_team=obj, result__home_team_score__gt=F('result__away_team_score')) 
     away_results = Q(away_team=obj, result__away_team_score__gt=F('result__home_team_score')) 
     results = self.fixtures(obj).filter(home_results | away_results) 
     return results.count() 

    def get_games_lost(self, obj): 
     home_results = Q(home_team=obj, result__home_team_score__lt=F('result__away_team_score')) 
     away_results = Q(away_team=obj, result__away_team_score__lt=F('result__home_team_score')) 
     results = self.fixtures(obj).filter(home_results | away_results) 
     return results.count() 

這一切工作正常,但對於8支球隊的聯賽,這可能需要大約5秒鐘以完成,因爲每個SerializerMethodField是一個單獨的查詢正在完成..

這個代碼的非api版本更簡單與單個查詢集註釋此序列化程序試圖創建的每個屬性,而不是單個查詢。

因此,對於給定的序列化程序,是否可以做同樣的事情,並從單個查詢而不是多個構建序列化程序數據?

回答

1

您可以在視圖集級別指定自定義查詢通過設置queryset屬性或重寫get_queryset

該查詢可能是你在非API版本使用同一個。

該方法的結果將直接饋送序列化程序,因此每個額外的註釋將在那裏可用。您可能需要使用read_only=True標誌在串行器中定義帶註釋的字段。

+0

哦,當然了!通過試圖僅使用序列化程序而不是視圖集中的可用內容,我認真地過度複雜化了這些...我稍後再嘗試一下,並相應地接受它。 – Sayse

1

夫婦可能的解決方案:

1)它們組合在一起成爲一個場

class TeamLeagueSerializer(ModelSerializer): 
    class Meta: 
     model = Team 
     fields = [...] 
    details = fields.SerializerMethodField() 

    def get_details(self, team): 
     #your non-api version of the code 
     return {games_played: fixtures, games_won: won, games_lost: lost} 

2)或者,如果你真的想保持API相同,另一種可能性是設置每個屬性作爲模型屬性,並有例如額外的緩存性能self._team_info保存查詢以備將來使用的結果:然後

class Team(models.Model): 
    #your fields 

    @property 
    def team_info(self): 
     if not hasattr(self, "_team_info"): 
       #Your non-api version of the code 
       self._team_info = #result of your query containing fixture info, games won, games lost, etc, .e.g. in a dictionary 
     return self._team_info 

    @property 
    def fixtures(self): 
     return self.team_info['fixtures'] 

    @property 
    def games_won(self): 
     return self.team_info['games_won'] 

    @property 
    def games_lost(self): 
     return self.team_info['games_won'] 

在seriali壽你不需要設置任何SerializerMethodFields,你可以參考games_won,games_lost和固定裝置在你的領域屬性:

class TeamLeagueSerializer(ModelSerializer): 
    class Meta: 
     model = Team 
     fields = [..., 'fixtures', 'games_won', 'games_lost'] 
+0

選項1可能必須與我一起去,但突出問題似乎是,這意味着這就意味着使用這些值它變成'instance.details.games_played',我不知道這是否是一個非常好的解決方案...我寧願不用api特定的代碼來稀釋我的模型,所以我沒有看到2作爲我的可行選項 – Sayse