简体   繁体   English

Django Rest Framework ModelSerializer自定义序列化器字段to_internal_value不会保存到对象

[英]Django Rest Framework ModelSerializer custom serializer field to_internal_value doesn't save to object

I have model and serializer, there is ArrayField(postgres) in that model. 我有模型和序列化器,该模型中有ArrayField(postgres)。

Now I wanted to create a serializer field that will receive list [1,2] and save it to object, but for a list and detail in serializer to show a list of JSON objects. 现在,我想创建一个序列化器字段,该字段将接收列表[1,2]并将其保存到对象,但是要在序列化器中获取列表和详细信息以显示JSON对象列表。

Model: 模型:

class User(models.Model):
    email = models.EmailField('Email', unique=True, blank=False)
    full_name = models.CharField(
        'Full name', max_length=150, blank=True, null=True)
    roles = ArrayField(
        models.PositiveSmallIntegerField(),
        default=list,
        blank=True
    )

Serializer: 串行:

class ArraySerializerField(ListField):

    def __init__(self, queryset, serializer_class):
        super(ArraySerializerField, self).__init__()
        self.queryset = queryset
        self.serializer_class = serializer_class

    def to_representation(self, value):
        if value:
            qs = self.queryset.filter(pk__in=value)
            return self.serializer_class(qs, many=True).data

        return []

    def to_internal_value(self, value):
        super(ArraySerializerField, self).to_internal_value(value)
        print(value)  # [1, 2]
        return value


class UserSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
    roles = ArraySerializerField(queryset=Role.objects.all(), serializer_class=RoleSerializer)

    class Meta:
        model = User
        fields = ('id', 'email', 'full_name', 'roles')

    def create(self, validated_data):
        print(validated_data) 
        # {'email': 'test@test.com', 'full_name': 'Test', 'roles': []}
        user = super(UserSerializer, self).create(validated_data)

        return user

Now when I do list or detail request, everything is ok, I get a list of roles as JSON. 现在,当我执行列表或详细信息请求时,一切正常,我得到了一个角色列表,如JSON。

But when I try to POST data and send with this data: 但是当我尝试发布数据并发送此数据时:

{
  "email": "test@test.com",
  "full_name": "Test",
  "roles": [1, 2]
}

validated_data in create method shows roles always as [] and object is saved without roles, but print from to_internal_value shows [1, 2] . create方法中的validated_data始终将角色显示为[]并且对象保存时没有角色,但是从to_internal_value打印显示[1, 2]

What am I doing wrong? 我究竟做错了什么? It should save sent data because to_internal_value works fine. 它应该保存发送的数据,因为to_internal_value可以正常工作。

EDIT: 编辑:

GET and LIST response gives me right format: GET和LIST响应给了我正确的格式:

{
  "id": 1,
  "email": "test@test.com",
  "full_name": "Test",
  "roles": [
    {
      "id": 1,
      "name": "Role 1"
    },
    {
      "id": 2,
      "name": "Role 2"
    }
  ]
}

Have you tried this? 你有尝试过吗?

class UserSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
    roles = serializers.ListField(child=serializers.IntegerField(), allow_empty=True, required=False)

    class Meta:
        model = User
        fields = ('id', 'email', 'full_name', 'roles')

    def create(self, validated_data):
        # check validated_data here
        ...

Note 注意

I'm not sure about the nature of SerializerExtensionsMixin class here. 我不确定SerializerExtensionsMixin类的性质。 Also I'm not sure the intention behind the queryset and serializer_class arguments of your custom ListField 另外我不确定您的自定义ListFieldquerysetserializer_class参数背后的意图


Django Shell Output Django Shell输出

In [7]: from rest_framework import serializers                                                                                                                                                                     

In [8]: class UserSerializer(serializers.Serializer):  # Created a simple serializer without model
   ...:     roles = serializers.ListField(child=serializers.IntegerField(), allow_empty=True, required=False) 
   ...:     email = serializers.EmailField() 
   ...:     full_name = serializers.CharField() 
   ...:                                                                                                                                                                                                            

In [9]: data = { # your data
   ...:   "email": "test@test.com", 
   ...:   "full_name": "Test", 
   ...:   "roles": [1, 2] 
   ...: }                                                                                                                                                                                                          

In [10]: u = UserSerializer(data=data)                                                                                                                                                                             

In [11]: u.is_valid()                                                                                                                                                                                              
Out[11]: True

In [12]: u.data  # got valid data                                                                                                                                                                                                  
Out[12]: {'roles': [1, 2], 'email': 'test@test.com', 'full_name': 'Test'}

In [13]: data["roles"] = [] # change data to accept empty list                                                                                                                                                                                       

In [14]: u = UserSerializer(data=data)                                                                                                                                                                             

In [15]: u.is_valid()                                                                                                                                                                                              
Out[15]: True

In [16]: u.data  # got validated data with empty list                                                                                                                                                                                                  
Out[16]: {'roles': [], 'email': 'test@test.com', 'full_name': 'Test'} 

In [17]: data["roles"] = ["foo","bar"]   #added string to the list                                                                                                                                                                          

In [18]: u = UserSerializer(data=data)                                                                                                                                                                             

In [19]: u.is_valid()  # validation failed                                                                                                                                                                                          
Out[19]: False

In [20]: u.errors                                                                                                                                                                                                  
Out[20]: {'roles': {0: [ErrorDetail(string='A valid integer is required.', code='invalid')], 1: [ErrorDetail(string='A valid integer is required.', code='invalid')]}}

UPDATE-1 UPDATE-1

Create a RoleSerializer and use it in the UserSerializer 创建一个RoleSerializer并在UserSerializer

class RoleSerializer(serializers.ModelSerializer): class Meta: model = Role fields = ('id', 'name')


class UserSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
    roles = serializers.ListField(child=serializers.IntegerField(), allow_empty=True, required=False)

    class Meta:
        model = User
        fields = ('id', 'email', 'full_name', 'roles')

    def create(self, validated_data):
        # check validated_data here
        ...

    def to_representation(self, instance): rep = super().to_representation(instance) rep['roles'] = RoleSerializer(Role.objects.filter(id__in=rep['roles']), many=True).data return rep

UPDATE-2 UPDATE-2

Using a custom array field 使用自定义数组字段

class ArrayField(serializers.ListField): def __init__(self, *args, **kwargs): self.queryset = kwargs.pop('queryset', None) self.serializer_class = kwargs.pop('serializer_class', None) super().__init__(*args, **kwargs) def to_representation(self, data): qs = self.queryset.filter(id__in=data) serializer = self.serializer_class(qs,many=True) return serializer.data

class UserSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
    roles = ArrayField(queryset=Role.objects.all(), serializer_class=RoleSerializer)

    class Meta:
        model = User
        fields = ('id', 'email', 'full_name', 'roles')

    def create(self, validated_data):
        # check validated_data here
        ...

Try switching to PrimaryKeyRelatedField . 尝试切换到PrimaryKeyRelatedField Though you'll need to change your user model to use an actual relation. 虽然您需要更改用户模型以使用实际关系。 Which is generally a good idea because it'll help enforce data integrity with your project. 通常这是一个好主意,因为它将帮助您的项目加强数据完整性。

class User(models.Model):
    email = models.EmailField('Email', unique=True, blank=False)
    full_name = models.CharField(
        'Full name', max_length=150, blank=True, null=True)
    roles = models.ManyToManyField(Role, blank=True)

class UserSerializer(SerializerExtensionsMixin, serializers.ModelSerializer):
    roles = serializers.PrimaryKeyRelatedField(
        many=True,
        queryset=Role.objects.all(),
    )

    class Meta:
        model = User
        fields = ('id', 'email', 'full_name', 'roles')

    def create(self, validated_data):
        print(validated_data) 
        # {'email': 'test@test.com', 'full_name': 'Test', 'roles': []}
        user = super(UserSerializer, self).create(validated_data)

        return user

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Django Rest Framework:将ModelSerializer作为ModelSerializer中的字段不显示选择 - Django Rest Framework: ModelSerializer as field in a ModelSerializer doesn't show choices Django rest 框架,序列化方法字段不保存对数据库的更改? - Django rest framework, serializer method field doesn't save changes to db? django rest 框架序列化程序 - 不返回空列表字段 - django rest framework serializer - doesn't return empty list field 如何在 Django REST Framework 的 RelatedField 类中自定义 to_internal_value 函数? - How to customize to_internal_value function in a RelatedField class for Django REST Framework? Django Rest Framework - 如何在 ModelSerializer 中添加自定义字段 - Django Rest Framework - How to add custom field in ModelSerializer Django Rest Framework ModelSerializer保存错误 - Django Rest Framework ModelSerializer save error Django REST Framework - ModelSerializer 中的附加字段 - Django REST Framework - Additional field in ModelSerializer Django REST Framework ModelSerializer-未保存对象 - Django REST Framework ModelSerializer - Object not saved Django rest框架ModelSerializer - Django rest framework ModelSerializer Django Rest Framework v3.0:如何在保存对象时将自定义序列化程序字段映射到模型字段? - Django Rest Framework v3.0 : How to map custom serializer fields to model field while saving an object?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM