Django Rest 框架多对多字段序列化

问题描述 投票:0回答:2

型号:

class MaterialAttribute(models.Model):
    """
    Represents a material attribute.

    Attributes:
        name (CharField): The name of the material attribute.
    """

    class Meta:
        verbose_name = "Material Attribute"
        verbose_name_plural = "Material Attributes"
        db_table = "material_attribute"

    name = models.CharField(max_length=255)

    def __str__(self):
        return f"{self.name}"


class MaterialType(models.Model):
    """
    Represents a material type.

    Attributes:
        name (CharField): The name of the material type.
        attributes (ManyToManyField): The attributes of the material type.
    """

    class Meta:
        verbose_name = "Material Type"
        verbose_name_plural = "Material Types"
        db_table = "material_type"

    name = models.CharField(max_length=255)
    attributes = models.ManyToManyField(
        MaterialAttribute, related_name="material_types"
    )

    def __str__(self):
        return f"{self.name}"

我想以这种方式编写一个 MaterialTypeSerializer,对于列表/检索它返回 Json 表示

{
        "id": 1,
        "name": "Test",
        "attributes": [
            {
                "id": 1,
                "name": "Format"
            },
            {
                "id": 2,
                "name": "Farbe"
            }
        ]
    } 

属性和创建/更新

{
"name": "Test",
        "attributes": [
            {
                1
            },
            {
                2
            }
        ] 
}

主键。

class MaterialAttributeSerializer(serializers.ModelSerializer):
    """
    Serializer for the MaterialAttribute model.

    This serializer includes the following fields:
    - id: The unique identifier of the material attribute.
    - name: The name of the material attribute.

    All fields are read-only.
    It is used to serialize minimal material attribute data.
    """

    class Meta:
        model = MaterialAttribute
        fields = ["id", "name"]


class MaterialAttributeManyField(serializers.PrimaryKeyRelatedField):
    
    def to_representation(self, value):
        return MaterialAttributeSerializer(value).data

class MaterialTypeSerializer(serializers.ModelSerializer):
    """
    Serializer for the MaterialType model.

    This serializer includes the following fields:
    - id: The unique identifier of the material type.
    - name: The name of the material type.
    - attributes: The attributes associated with the material type.

    All fields are read-only.
    It is used to serialize minimal material type data.
    """

    attributes = MaterialAttributeManyField(
        queryset=MaterialAttribute.objects.all(), many=True
    )

    class Meta:
        model = MaterialType
        fields = ["id", "name", "attributes"]

但是,这会导致“不可散列的类型:'ReturnDict'”

我尝试不重写序列化器的创建和更新方法,以保持代码简单。

如果有人知道解决这个问题的干净方法,我会很感激

django django-rest-framework
2个回答
0
投票

要在 Django REST Framework (DRF) 中正确序列化 ManyToManyField 以进行列表/检索和创建/更新操作,您需要自定义序列化器以正确处理关系。

序列化器.py

from rest_framework import serializers
from .models import MaterialAttribute, MaterialType

class MaterialAttributeSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = MaterialAttribute
        fields = ["id", "name"]

class MaterialTypeSerializer(serializers.ModelSerializer):
    attributes = serializers.PrimaryKeyRelatedField(queryset=MaterialAttribute.objects.all(), many=True)

    class Meta:
        model = MaterialType
        fields = ["id", "name", "attributes"]

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        representation['attributes'] = MaterialAttributeSerializer(instance.attributes.all(), many=True).data
        return representation

    def create(self, validated_data):
        attributes_data = validated_data.pop('attributes', [])
        material_type = MaterialType.objects.create(**validated_data)
        for attr_id in attributes_data:
            attribute = MaterialAttribute.objects.get(id=attr_id)
            material_type.attributes.add(attribute)
        return material_type

    def update(self, instance, validated_data):
        attributes_data = validated_data.pop('attributes', [])
        instance.name = validated_data.get('name', instance.name)
        
        instance.attributes.clear()
        for attr_id in attributes_data:
            attribute = MaterialAttribute.objects.get(id=attr_id)
            instance.attributes.add(attribute)
        
        instance.save()
        return instance

解释

MaterialAttributeSerializer:

这个序列化器很简单,将 MaterialAttribute 实例序列化为带有字段 id 和 name 的 JSON 格式。

材质类型序列化器:

对于列表/检索,它重写 to_representation 以提供自定义序列化,其中属性表示为字典列表({“id”:1,“name”:“Format”})。 对于创建/更新,它重写创建和更新方法来处理ManyToManyField关系。创建或更新 MaterialType 时,您可以将属性作为 MaterialAttribute 的 id 列表传递。

希望这有帮助!


0
投票
from rest_framework import serializers
from .models import Article, Tag


class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ("id", "name")


class ArticleSerializer(serializers.ModelSerializer):

    tags = serializers.PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all())

    class Meta:
        model = Article
        fields = ("id", "title", "tags")
        
    def to_representation(self, instance):
        representation = super().to_representation(instance)
        representation["tags"] = TagSerializer(instance.tags.all(), many=True).data
        return representation

我认为这个例子的工作原理实际上是一样的。

© www.soinside.com 2019 - 2024. All rights reserved.