首页 文章

Django REST Serializer方法可写字段

提问于
浏览
9

我正在阅读Django REST Framework,我有一个使用SerializerMethodField()与getter序列化的模型 .

但是,当我POST到此 endpoints 时,我希望能够设置此字段,但这不起作用,因为正如上面的文档所示,您无法写入SerializerMethodField . Django REST中是否有任何方法可以为您定义自定义getter方法的序列化器字段,以及自定义setter方法?

编辑:这是我正在尝试做的事情的来源 . 客户与用户具有一对一的关系 .

class ClientSerializer(serializers.ModelSerializer):
    email = serializers.SerializerMethodField()

    def create(self, validated_data):
        email = validated_data.get("email", None) # This doesn't work because email isn't passed into validated_data because it's a readonly field
        # create the client and associated user here


    def get_email(self, obj):
        return obj.user.email

    class Meta:
        model = Client
        fields = (
            "id",
            "email",
        )

4 回答

  • 2

    您需要使用其他类型的字段:

    class ClientSerializer(serializers.ModelSerializer):
        email = serializers.EmailField(source='user.email')
    
        def create(self, validated_data):
            # DRF will create object {"user": {"email": "inputed_value"}} in validated_date
            email = validated_data.get("user", {}).get('email')
    
        class Meta:
            model = Client
            fields = (
                "id",
                "email",
            )
    
  • -1

    为什么不在视图中创建客户端呢?

    def post(self, request, *args, **kwargs):
        data = {
            'email': request.data.get('email'),
        }
    
        serializer = ClientSerializer(data=data)
        if serializer.is_valid():
            email = serializer.data.get('email')
            client = Client.objects.create(email=email)
            # do other stuff
    
  • 0

    我遇到了同样的问题,并提出了以下解决方案 .

    请注意,我确实需要在序列化程序中使用 SerializerMethodField ,因为我需要根据 request.user 和某些权限填充字段,这对于 SerializerField 或其他答案中提出的其他解决方案来说太复杂了 .

    解决方案是API视图的 perform_update ,并在那时执行特定的写入(在我的情况下,使用另一个Serializer在正常的顶部) . 我只需要在更新时执行此操作,但如果这是您的用例,则可能需要使用 perform_create .

    它是这样的:

    def perform_update(self, serializer):
            if 'myField' in self.request.data and isinstance(self.request.data['myField'], bool):
            if self.request.user == serializer.instance.owner:
                serializer.instance.myField = self.request.data['myField']
            else:
                # we toggle myField in OtherClass
                try:
                    other = models.OtherClass.objects.get(...)
                except models. OtherClass.DoesNotExist:
                    return Response("You don't sufficient permissions to run this action.", status=status.HTTP_401_UNAUTHORIZED)
                except models.OtherClass.MultipleObjectsReturned:  # should never happen...
                    return Response("Internal Error: too many instances.", status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                else:
                    data = {
                        'myField': self.request.data['myField']
                        ... # filled up with OtherClass params
                    }
                    otherSerializer = serializers.OtherClassSerializer(other, data=data)
                    if otherSerializer.is_valid():
                        otherSerializer.save()
        serializer.save()  # takes care of all the non-read-only fields
    

    我必须承认,根据MVC模式,它并不理想,但它确实有效 .

  • 0

    你可以重复 email 字段,它可以工作,但它可能会让人感到困惑

    class ClientSerializer(serializers.ModelSerializer):
        email = serializers.SerializerMethodField()
        email = serializers.EmailField(required=False)
    
        def create(self, validated_data):
            email = validated_data.get("email", None) # This doesn't work because email isn't passed into validated_data because it's a readonly field
            # create the client and associated user here
    
    
        def get_email(self, obj):
            return obj.user.email
    
        class Meta:
            model = Client
            fields = (
                "id",
                "email",
            )
    

相关问题