在序列化器中创建时更改返回类型

时间:2018-07-21 06:26:16

标签: django django-rest-framework

我有以下两个序列化器:

class RankingVC: UIViewController {

@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
    super.viewDidLoad()
    setupCollectionViewDelegates()
    registerCells()
    view.backgroundColor = .red
}
}

extension RankingVC  : UICollectionViewDelegate, UICollectionViewDataSource {

    func setupCollectionViewDelegates() {
        collectionView.delegate = self
        collectionView.dataSource = self
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifier.rankingCVCell, for: indexPath) as! RankingCVCell
        return cell 
    }

    func registerCells() {
        RegisterCVCells.registerCell(withNibName: CellIdentifier.rankingCVCell, forCollectionView: collectionView)
    }
}

它们基于以下模型:

class ProgramSerializer(serializers.ModelSerializer):
    class Meta:
        from radio.models import Program
        model = Program
        fields = ('id', 'title')

class UserRecentlyPlayedSerializer(serializers.ModelSerializer):
    program_data = ProgramSerializer(read_only=True)
    class Meta:
        model = UserRecentlyPlayed
        fields = ('id', 'user', 'program', 'program_data',)

我要执行的操作如下:在创建时,我希望能够通过以下方式创建UserRecentlyPlayed的新实例:

class Program(models.Model):
    title = models.CharField(max_length=64)

class UserRecentlyPlayed(models.Model):
    user = models.ForeignKey(User)
    program = models.ForeignKey(Program)

但是,当我返回列表时,我想返回以下内容:

{
    "user": "...user id ....",
    "program": "....program id...."
}

这些在以下视图中被调用:

[{
     "id": "... id .... ",
     "user": ".... user id .....",
     "program": {"id": "...program id...", "title": "...title..." }
 }]

不幸的是,这不起作用。正确的魔术是什么?

3 个答案:

答案 0 :(得分:1)

您可以将序列化器中的program_data重命名为program,也可以为嵌套序列化器指定源。

那应该返回列表的输出。

class UserRecentlyPlayedSerializer(serializers.ModelSerializer):
    program = ProgramSerializer(read_only=True)
    class Meta:
        model = UserRecentlyPlayed
        fields = ('id', 'user', 'program',)

class UserRecentlyPlayedSerializer(serializers.ModelSerializer):
    program_data = ProgramSerializer(read_only=True, source='program')
    class Meta:
        model = UserRecentlyPlayed
        fields = ('id', 'user', 'program_data',)

要支持创建相同的json输入,最简单的方法是创建另一个序列化程序用于输入:

class UserRecentlyPlayedSerializerInput(serializers.ModelSerializer):
    program = serializers.PrimaryKeyRelatedField(queryset=Program.objects.all())

    class Meta:
        model = UserRecentlyPlayed
        fields = ('id', 'user', 'program',)

并在请求为POST / PUT / PATCH时在您的视图中使用它:

class RecentlyPlayed(generics.ListCreateAPIView):
    serializer_class = UserRecentlyPlayedSerializer    

    def get_serializer_class(self):
        if self.request.method.lower() == 'get':
            return self.serializer_class

        return UserRecentlyPlayedSerializerInput
  

虽然这很适合“获得”,但我希望看到同样的结果   创建后的结果。我仍然看到{“ program”:“ ... id ....”

为此,您必须在视图中稍微更改create方法的实现

   def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        instance = serializer.save()
        headers = self.get_success_headers(serializer.data)

        oser = UserRecentlyPlayedSerializer(instance)

        return Response(oser.data, status=status.HTTP_201_CREATED, 
headers=headers)

答案 1 :(得分:0)

首先在模型中创建一个名为program_data的属性

class Program(models.Model):
    title = models.CharField(max_length=64)

class UserRecentlyPlayed(models.Model):
    user = models.ForeignKey(User)
    program = models.ForeignKey(Program)

    @property
    def program_data(self):
        return self.program

然后在序列化程序中,您无需更改任何内容,它将保持与以下相同

class ProgramSerializer(serializers.ModelSerializer):
    class Meta:
        from radio.models import Program
        model = Program
        fields = ('id', 'title')

class UserRecentlyPlayedSerializer(serializers.ModelSerializer):
    program_data = ProgramSerializer(read_only=True)
    class Meta:
        model = UserRecentlyPlayed
        fields = ('id', 'user', 'program', 'program_data',)

答案 2 :(得分:0)

好吧,我朝一个略有不同的方向走了,而且行得通。我没有使用ListCreateAPIView,而是使用ListModeMixin,CreateModelMixin和GenericAPIView创建了自己的类。魔术是覆盖def list类。我还实现了“ return_serializer_class”属性。就是这样。

class RecentlyPlayed(mixins.ListModelMixin,
                     mixins.CreateModelMixin,
                     generics.GenericAPIView):
    serializer_class = UserRecentlyPlayedSerializer
    return_serializer_class = ProgramSerializer

    parser_classes = (JSONParser, MultiPartParser)

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.create(request, *args, **kwargs)
        return self.list(request, *args, **kwargs)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.return_serializer_class(queryset, many=True)
        return Response({'recently_played': serializer.data})