Django - 基于外键将属性添加到序列化器和订单列表

时间:2018-03-13 05:21:08

标签: python django django-rest-framework

我试图获取基于外键的数据。 让我们说我有这些模型:

# models.py
class Player(models.Model):
    name = models.CharField(max_length = 64)

class Game(models.Model):
    score = models.IntegerField()
    player = models.ForeignKey('Player', models.DO_NOTHING, related_name='player', blank=False, null=False)

class InjuredPlayer(models.Model):
    player = models.ForeignKey('Player', models.DO_NOTHING, blank=False, null=False)

我使用REST框架,所以我有这个序列化程序。我想添加一个属性,该属性是所有游戏分数与玩家序列化程序的总和。

# Serializer
class PlayerSerializer(serializers.ModelSerializer):
    # Get the sum of Game scores of the player
    # sum_of_scores = ________________
  class Meta:
    model = Player
    # Use sum_of_scores as a field on the serializer
    fields = ('activity', 'logo', 'sum_of_scores')

然后,想要做的是显示玩家列表及其得分总和,如果他们在InjuredPlayer上。所以在我的班上:

class PlayerList(APIView)

查询集应该类似于:

# I tried this
queryset = Player.objects.filter(injuredplayer__player=id)

如何过滤不在另一个表上的对象。 是否可以根据sum_of_scores订购列表?如果是这样,怎么样? 谢谢

1 个答案:

答案 0 :(得分:2)

如果您想获得序列化程序中所有字段的总和,请使用 serializerMethodField

from django.db.models import Sum
# also import Game model
class PlayerSerializer(serializers.ModelSerializer):
    sum_of_scores = serializers.SerializerMethodField()

    class Meta:
        model = Player
        fields = ('id', 'name', 'sum_of_scores')

    def get_sum_of_scores(self, obj):
        return Game.objects.filter(player=obj).aggregate(Sum('score'))

注意 您的模型结构不是最佳的,您可以将 InjuredPlayer 模型和新字段移除到播放器,例如 is_injured 。并将其设置为默认值false。而且游戏模型的相关名称应该是“游戏”或其他东西。这样你就可以轻松反向引用。在您当前的结构中,要获得与玩家相关的所有游戏,您应该调用player.player.all()。如果你把它改成游戏,那将是player.games.all()

所以新结构应该是

# models.py
class Player(models.Model):
    name = models.CharField(max_length = 64)
    is_injured = models.BooleanField(dafault=False)

class Game(models.Model):
    score = models.IntegerField()
    player = models.ForeignKey('Player', models.DO_NOTHING, related_name='games', blank=False, null=False)

串行器变为​​

# Serializer
from django.db.models import Sum
class PlayerSerializer(serializers.ModelSerializer):
    sum_of_scores = serializers.SerializerMethodField()

    class Meta:
        model = Player
        fields = ('id', 'name', 'is_injured', 'sum_of_scores')

    def get_sum_of_scores(self, obj):
        return obj.games.all().aggregate(Sum('score'))