使用Django REST通过一个额外的字段序列化多对多关系

时间:2017-08-31 21:12:47

标签: python django django-rest-framework

我有一个简单的模型,其中User可以参与多个Game,而Game可以由多个User播放。每个Userscore中都有一个Game字段。

为了达到这个目的,我已经按照Django文档中提供的示例,通过创建第三个模型ManyToMany来链接Membership表来实现与其他字段的Game关系和User一个。

我有以下models.py

from django.contrib.auth.models import AbstractUser
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
from django.db import models

class User(AbstractUser):
    pass

# triggered as soon as a new user is saved in the db
@receiver(post_save, sender=User)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    if created:
        Token.objects.create(user=instance)


class Game(models.Model):
    users = models.ManyToManyField(User, through='Membership')


class Membership(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    game = models.ForeignKey(Game, on_delete=models.CASCADE)
    score = models.IntegerField()

然后我写了serializers.py

from rest_framework import serializers
from .models import User, Membership, Game


class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        # unique email
        model._meta.get_field('email').__dict__['_unique'] = True
        fields = ('id', 'username', 'password', 'email')

    def create(self, validated_data):
        user = super().create(validated_data)
        if 'password' in validated_data:
                user.set_password(validated_data['password'])
                user.save()
        return user

class GameSerializer(serializers.ModelSerializer):

    users = UserSerializer(many=True)

    class Meta:
        model = Game
        fields = ('users',)

class MembershipSerializer(serializers.HyperlinkedModelSerializer):

    id = serializers.ReadOnlyField(source='game.id')

    class Meta:
        model = Membership

        fields = ('id', 'score')

我的目标是通过发布以下内容来保存新的Game

{ 
{user_id = 1,
score = 25},
{user_id = 2,
score = 10}
}

我因此想知道如何实现这一目标。

2 个答案:

答案 0 :(得分:0)

要实现这一目标,您可以使用Django通用视图,您可以在其中创建CreateAPI视图,在每个游戏之后您可以创建一个成员资格对象。

但是你必须使用ModelSerializer而不是HyperlinkedModelSerializer。

答案 1 :(得分:0)

手动执行以下操作:

serializers.py

class MembershipSerializer(serializers.ModelSerializer):
    class Meta:
        model = Membership
        fields = ('user ', 'game', 'score')

views.py

class GameViewSet(ModelViewSet):
    queryset = Game.objects.all()
    serializer_class = GameSerializer
    permission_classes = (IsAuthenticated,)

    @detail_route(methods=['POST'])
    def bulk_create(self, request, pk):
        game = self.get_object()
        datas = request.data.getlist('data')
        import ast
        for _data in datas:
            data = ast.literal_eval(_data)
            data['game'] = game.id
            serializer = MembershipSerializer(data=data)
            if serializer.is_valid()
                serializer.save()
            else:
                pass
        return Response('success')

您发布的数据类似{'data':[{user_id = 1,score = 25}]}

帖子网址为/game/your_game_id/bulk_create/, 不是测试代码,你可能会遇到一些错误,但你可以这样做。