型号:
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 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 列表传递。
希望这有帮助!
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
我认为这个例子的工作原理实际上是一样的。