代码之家  ›  专栏  ›  技术社区  ›  hancho

Django Rest Framework SerializerMethodField仅在GET请求时

  •  0
  • hancho  · 技术社区  · 7 年前

    我的DRF后端遇到了一个小问题。

    我正在用某些模型的选项填充字段。

    我对一个型号有外键要求。创建模型时,我希望将其保存在外部id下。

    当我请求模型时,我希望模型中包含选项字段映射到的任何内容。

    我可以使用SerializerMethodField来完成这项工作,但是当我尝试创建模型时,由于块无效,我得到一个400错误。如果删除SerializerMethodField,我可以保存,但可以从请求中获取数据库中存储的号码。

    任何帮助都将不胜感激。

    class BlockViewSet(ModelViewSet):
        model = apps.get_model('backend', 'Block')
        queryset = model.objects.all()
        serializer_class = serializers.BlockSerializer
        permissions = ('All',)
    
        def create(self, request, format=None):
            data = request.data 
            data['user'] = request.user.id
            data['goal'] = WorkoutGoal.objects.get(goal=data['goal']).id
            block = serializers.BlockSerializer(data=data, context={'request': request})
            if block.is_valid():
                new_block = block.save()
                return Response({'block': {'name': new_block.name, 'id': new_block.id}}, status=status.HTTP_201_CREATED)
            else:
                return Response(block.errors, status=status.HTTP_400_BAD_REQUEST)
    
    class WorkoutGoalSerializer(serializers.ModelSerializer):
        class Meta:
            model = apps.get_model('backend', 'WorkoutGoal')
            fields = ('goal',)
    
        goal = serializers.SerializerMethodField(read_only=True, source='get_goal')
    
        def get_goal(self, obj):
            return dict(WorkoutGoal.GOALS).get(obj.goal)
    
    class BlockSerializer(serializers.ModelSerializer):
        workout_count = serializers.IntegerField(required=False)
        completed_workouts = serializers.IntegerField(required=False)
        goal = WorkoutGoalSerializer()
    
        class Meta:
            model = apps.get_model('backend', 'Block')
            read_only_fields = ('workout_count', 'completed_workouts')
            fields = read_only_fields + ('id', 'name', 'user', 'created', 'goal')
    

    上面的代码返回正确的选择,但我无法保存在下面。移除 goal = WorkoutGoalSerializer() 它保存但不返回映射的选择。

    2 回复  |  直到 7 年前
        1
  •  2
  •   JPG    7 年前

    我想这会很有魅力的,

    class WorkoutGoalSerializer(serializers.ModelSerializer):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            if 'request' in self.context and self.context['request'].method == 'GET':
                self.fields['goal'] = serializers.SerializerMethodField(read_only=True, source='get_goal')
    
        class Meta:
            model = apps.get_model('backend', 'WorkoutGoal')
            fields = ('goal',)
    
        goal = serializers.SerializerMethodField(read_only=True, source='get_goal')  # remove this line
    
        def get_goal(self, obj):
            return dict(WorkoutGoal.GOALS).get(obj.goal)

    这是怎么回事?
    它将重新启动 goal 字段 SerializerMethodField ,如果重新计算的方法是 GET .

    记住一件事, 你应该把线拔掉 ,

    goal = serializers.SerializerMethodField(read_only=True, source='get_goal')

        2
  •  0
  •   Ykh    7 年前

    序列化程序.py

    class BlockCreateSerializer(serializers.ModelSerializer):
        workout_count = serializers.IntegerField(required=False)
        completed_workouts = serializers.IntegerField(required=False)
    
        class Meta:
            model = apps.get_model('backend', 'Block')
            read_only_fields = ('workout_count', 'completed_workouts')
            fields = read_only_fields + ('id', 'name', 'user', 'created', 'goal')
    
    class BlockSerializer(serializers.ModelSerializer):
        workout_count = serializers.IntegerField(required=False)
        completed_workouts = serializers.IntegerField(required=False)
        goal = WorkoutGoalSerializer()
    
        class Meta:
            model = apps.get_model('backend', 'Block')
            read_only_fields = ('workout_count', 'completed_workouts')
            fields = read_only_fields + ('id', 'name', 'user', 'created', 'goal')
    

    视图.py

    class BlockViewSet(ModelViewSet):
        model = apps.get_model('backend', 'Block')
        queryset = model.objects.all()
        serializer_class = serializers.BlockSerializer
        permissions = ('All',)
    
        def get_serializer_class(self):
            if self.action == 'create':
                return serializers.BlockCreateSerializer
            else:
                return self.serializer_class
    
        def create(self, request, format=None):
            data = request.data 
            data['user'] = request.user.id
            data['goal'] = WorkoutGoal.objects.get(goal=data['goal']).id
            block = self.get_serializer(data=data)
            if block.is_valid():
                new_block = block.save()
                return Response({'block': {'name': new_block.name, 'id': new_block.id}}, status=status.HTTP_201_CREATED)
            else:
                return Response(block.errors, status=status.HTTP_400_BAD_REQUEST)
    

    覆盖 get_serializer_class 返回不同的 serializer_class 对于 create 以及其他行动( list\retrieve\update\partial_update )

    推荐文章