简体   繁体   中英

Django/DRF - prefetch_related() returning all objects without properly matching the foreign key relationship?

So hey guys I've been running into a problem with my endpoints. I've been trying to use return Player.objects.prefetch_related('playerstatistic_set') to return me the Player objects that match with the objects in the PlayerStatistic model. The PlayerStatistic table currently only has one row so player_id = 1 should be the only one returned but currently the prefetch_related() returns ALL of the Player objects.

I've tried going into the PlayerStatistic model and adding a related_name like so - player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name='player_stats') and changing the prefetch to prefetch_related('player_stats') but that still just returns all the Player objects as well.

Models -


class Player(models.Model):
    # class for Player model
    name = models.CharField(max_length=100)
    team = models.ForeignKey(Team, on_delete=models.CASCADE)


class Game(models.Model):
    # class for Game model

    home_team = models.ForeignKey(Team, related_name='home_games',
                                     on_delete=models.CASCADE)
    away_team = models.ForeignKey(Team, related_name='away_games',
                                     on_delete=models.CASCADE)
    date = models.DateField()


class PlayerStatistic(models.Model):
    # class for individual player statistics

    game = models.ForeignKey(Game, on_delete=models.CASCADE)
    player = models.ForeignKey(Player, on_delete=models.CASCADE)
    team = models.ForeignKey(Team, on_delete=models.CASCADE)
    points = models.IntegerField()
    assists = models.IntegerField()
    rebounds = models.IntegerField()

My get_queryset function in my Player View -

class PlayerViewSet(viewsets.ModelViewSet):
    # ViewSet to display Players

    queryset = Player.objects.all()
    serializer_class = PlayerSerializer

    def get_queryset(self):
        return queryset.prefetch_related('playerstatistic_set')

Of course in my Player Serializer I've tried nesting the PlayerStatistic Serializer in there as well but the result seems to be the same whether I have the nested serializer or not.

{id: 1, game_id: 1, player_id: 1, team_id: 1, points: 20, assists: 10, rebounds: 2}

That row is the only row in PlayerStatistic, so the Player object with player_id=1 should be returned but all rows are returned (12 rows).

EDIT - Serializers below -


class PlayerStatisticSerializer(serializers.ModelSerializer):
    # Serializer for player statistics object

    class Meta:
        model = PlayerStatistic
        fields = '__all__'


class PlayerSerializer(serializers.ModelSerializer):
    # Serializer for Player objects
    playerstatistic = PlayerStatisticSerializer(many=True, read_only=True)

    class Meta:
        model = Player
        fields = '__all__'

You might be confused in the function of prefetch_related, in your example everything is working as expected. Player.objects.all() this returns all the Player objects and this queryset.prefetch_related('playerstatistic_set') won't change the query results but only prefetches related objects as a query optimizer.

If you want to query only Players who have Player statistics you'll have to work the other way around, ie by selecting player statistics and using Player as nested serializer in PlayerStatisticSerializer .


Other quick way to achive what you want with your codebase would be remove all users without playerstatistic_set with a .filter method

def get_queryset(self):
    return queryset.prefetch_related('playerstatistic_set').filter(playerstatistic_set__isnull=False)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM