2017-02-24 3 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 버전은 개별 쿼리가 아닌이 serializer가 만드는 각 속성에 주석을 달아주는 단일 쿼리 세트로 훨씬 간단합니다.

주어진 serializer에 대해 동일한 작업을 수행하고 여러 쿼리 대신 하나의 쿼리에서 serializer 데이터를 구성 할 수 있습니까? 가능한 해결책의

답변

1

당신은 뷰셋 수준에서 사용자 지정 쿼리를 지정할 수 있습니다 queryset 속성 또는 오버라이드 (override)를 설정하여 get_queryset.

그 쿼리는 잠재적으로 당신이 아닌 API 버전에서 사용하는 것과 동일한 하나가 될 수 있습니다.

결과로 직렬화 기가 직접 피드되므로 모든 추가 주석을 사용할 수 있습니다. 당신은 read_only=True 깃발과 함께 Serializer에 주석 필드를 정의해야 할 수도 있습니다.

+0

물론 이죠! 나는 진지하게 viewset보다는 serializer에서 사용 가능한 것을 사용하려고 노력함으로써 지나치게 복잡하게 만들었습니다 ... 아쉽게도 나중에 시도해보고이를 받아들이십시오 .... – Sayse

1

커플 : 당신이 정말로 동일한 API를 유지하려는 경우

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)으로는 또는 또 다른 가능성은 각을 설정하는 것입니다 모델에 속성으로 속성, 나중에 사용하기 위해 쿼리의 결과를 저장하는 self._team_info 예를 들어, 추가 캐시 속성이 다음 seriali에 그런

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'] 

을 ZER 방금 games_won을 참조 할 수 있습니다, 어떤 SerializerMethodFields을 설정할 필요가 없습니다, 당신의 분야에서 games_lost 및 비품은 속성 :

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

옵션 1은 내가 가지고있는 것과 함께 있어야 할 수도 있지만, 주목해야 할 것은이 값을 사용한다는 의미 인 것처럼 보일 것입니다.이 값을 사용하면 'instance.details.games_played'가됩니다. 아주 좋은 해결책 ... 나는 오히려 내 모델을 API의 특정 코드로 희석시키지 않을 것이다. 그래서 나는 2를 나를 위해 실행 가능한 옵션으로 보지 않는다. – Sayse

관련 문제