【问题标题】:postman only showing "This field is required" to ManyToMany field in django邮递员只向 Django 中的 ManyToMany 字段显示“此字段是必需的”
【发布时间】:2021-10-08 05:05:53
【问题描述】:

我有 2 个模型 - 模块和房间。一个模块可以有零个或多个房间,一个房间可以添加到多个模块中。因此,它们之间存在简单的多对多关系。

当我使用发布请求时,原始数据有效,但表单数据无效。

模块/models.py -

class Module(models.Model):
    module_id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=100)
    desc = models.TextField()
    room_list = models.CharField(max_length = 100, blank=True)
    rooms = models.ManyToManyField(Rooms, blank=True)

rooms/models.py -

class Rooms(models.Model):
    room_id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=100)
    level = models.CharField(max_length=100)
    desc = models.TextField()

模块/serializers.py -

class ModuleSerializer(serializers.ModelSerializer):
    rooms = RoomSerializer(many=True)

    class Meta:
        model = Module
        fields = '__all__'

    def create(self, validated_data):
        rooms_data = validated_data.pop('rooms')
        module = Module.objects.create(**validated_data)
        for data in rooms_data:
            room = Rooms.objects.get(**data)
            module.rooms.add(room)
        return module

    def update(self, instance, validated_data):

        # Updating rooms
        rooms_data = validated_data.get('rooms')
        instance.rooms.clear()
        
        for room_data in rooms_data:
            room = Rooms.objects.get(**room_data)
            instance.rooms.add(room)
        
        # Updating other fields
        fields = [
            'title',
            'desc',
            'thumbnail',
            'is_deleted',
        ]
        for field in fields:
            setattr(instance, field, validated_data[field])
        instance.save()
        return instance

rooms/serialier.py -

class RoomSerialize(serializers.ModelSerializer):
    room_id = serializers.IntegerField()
    class Meta:
        model = Rooms
        fields = "__all__"

模块/views.py -

class add_module(APIView):
    def post(self, request, format=None):
    
        # Adding the rooms to module from room_list
        new_request = request.data.copy()
        room_list=[]
        if 'room_list' in new_request:
            room_list_data = list(new_request['room_list'].split(" "))
            for room in room_list_data:
                room_object = Rooms.objects.get(room_id=room)
                room_serializer = RoomSerializer(room_object)
                room_list.append(room_serializer.data)
        new_request.update({'rooms':room_list})
    
        # creating the module
        module_serializer = ModuleSerializer(data=new_request)
        if module_serializer.is_valid():
            module_serializer.save()
            return Response(module_serializer.data['module_id'])
        return Response(module_serializer.errors)

用于在 POSTMAN 中更新模块的 POST 请求正文 -

{
    "module_id": 2,
    "room_list": "1 2",
    "title": "4",
    "desc": "22",
}

请注意,在输入 ManyToMany 字段 - “rooms”时,我将字符串“room_list”作为包含要包含的所有 room_ids 的输入。当我在邮递员中将输入作为原始数据时,这非常有效,但是当我使用表单数据时,它会显示

{
    "rooms": [
        "This field is required."
    ]
}

怎么办?

【问题讨论】:

    标签: django django-models django-rest-framework django-views manytomanyfield


    【解决方案1】:

    首先,具有 (many=True) 的序列化器字段创建嵌套对象。 如果您输入带有Rooms 已序列化的数据,则意味着您创建了其他Rooms 实例。它将与if module_serializer.is_valid(): 部分一起显示。因此,如果您打算将已实例化的Rooms 链接到Module,则最好将其作为主键列表。

    这是我的示例代码。

    class ModuleSerializer(serializers.ModelSerializer):
        rooms = RoomSerializer(many=True, read_only=True)
    
        def create(self, validated_data):
            rooms_data = validated_data['room_list']
            module = Module.objects.create(**validated_data)
            for data in rooms_data.split(' '):
                room = Rooms.objects.get(room_id=data)
                module.rooms.add(room)
            return module
    
        def update(self, instance, validated_data):
    
            # Updating rooms
            rooms_data = validated_data.get('rooms')
            instance.rooms.clear()
    
            for room_data in rooms_data:
                room = Rooms.objects.get(**room_data)
                instance.rooms.add(room)
    
            # Updating other fields
            fields = [
                'title',
                'desc',
                'thumbnail',
                'is_deleted',
            ]
            for field in fields:
                setattr(instance, field, validated_data[field])
            instance.save()
            return instance
    
        class Meta:
            model = Module
            fields = '__all__'
    
    class AddModule(APIView):
        def post(self, request, format=None):
            # creating the module
            module_serializer = ModuleSerializer(data=request.data)
            if module_serializer.is_valid():
                module_serializer.save()
                return Response(module_serializer.data['module_id'])
            return Response(module_serializer.errors)
    

    任何其他部分与您的相同。无论是form-data还是json原始数据发送的数据,结果都如下。

    【讨论】:

    • 感谢您的惊人努力。成功了!
    • 还有一点,django中没有list字段。有没有办法将 room_list 输入为列表而不是字符串?
    • 如果您在 Module Serializer 的 RoomSerializer 字段中删除 read_only=True 选项,您可以将房间作为列表接收。但是,drf 序列化程序会尝试使用该数据创建新的 Rooms 实例。如果你想通过序列化器在房间和模块之间建立关系,PrimaryKeyField 可以是一个选项。您可以接收带有房间主键列表的数据。但是,如果您想将此字段与序列化一起使用,则应覆盖 to_representation 方法。
    猜你喜欢
    • 1970-01-01
    • 2011-08-13
    • 2016-04-29
    • 2021-10-18
    • 1970-01-01
    • 2012-12-02
    • 2021-04-10
    • 2021-06-14
    相关资源
    最近更新 更多