在 Django Rest Framework 中将字段分解为自己的序列化程序
Break up field into its own serializer in Django Rest Framework
假设我有简单的 Product
Django 模型:
class Product:
name = models.CharField(max_length=255, unique=True)
created_on = models.DateField()
我正在使用 Django Rest Framework 序列化此模型。我想将 created_on
分解成它自己的对象(包括 GET 请求的响应和 POST 请求中的有效负载):
{
"name": "MyProduct",
"created_on": {
"year": 2020,
"month": 1,
"day": 24
}
}
这是我目前的情况:
class DateSerializer(serializers.Serializer):
year = serializers.IntegerField()
month = serializers.IntegerField()
day = serializers.IntegerField()
def validate(data):
return datetime.date(data["year"], data["month"], data["day"])
class ProductSerializer(serialzers.ModelSerializer):
created_on = DateSerializer()
class Meta:
model = Friend
fields = ("name", "created_on")
def create(self, validated_data):
return Product.objects.create(**validated_data)
class ProductViewset(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
这种方法适用于 GET 请求(也就是说,我得到上面的 json)。但是,它不适用于 POST 请求(有效负载是上面的 json)。响应是 400
状态代码和消息 {'created_on': [ErrorDetail(string='This field is required.', code='required')]}
.
如果我将 required=False
传递给 DateSerializer
,我会看到 create
方法中的 self.initial_data
是 <QueryDict: {'name': ['MyProduct'], 'created_on': ['year', 'month', 'day']}>
。所以这些值由于某种原因消失了。
知道我在这里做错了什么以及如何让它工作吗?
class DateSerializer(serializers.Serializer):
year = serializers.IntegerField()
month = serializers.IntegerField()
day = serializers.IntegerField()
def to_internal_value(data):
return datetime.date(data["year"], data["month"], data["day"])
覆盖validate(...)
方法 ProductSerializer
class as,
<b>from datetime import date</b>
class DateSerializer(serializers.Serializer):
year = serializers.IntegerField()
month = serializers.IntegerField()
day = serializers.IntegerField()
class ProductSerializer(serializers.ModelSerializer):
created_on = DateSerializer()
<b>def validate(self, attrs):
super().validate(attrs)
attrs['created_on'] = date(**attrs['created_on'])
return attrs</b>
class Meta:
model = Product
fields = ("name", "created_on")
示例:
In [8]: payload = {"name": "MyProduct", "created_on": {"year": 2020, "month": 1, "day": 24}}
In [9]: serializer = ProductSerializer(data=payload)
In [10]: serializer.is_valid(True)
Out[10]: True
In [11]: serializer.validated_data
Out[11]:
OrderedDict([('name', 'MyProduct'),
('created_on', datetime.date(2020, 1, 24))])
In [12]: product_instance = serializer.save()
In [13]: product_instance.__dict__
Out[13]:
{'_state': <django.db.models.base.ModelState at 0x7f75c0629978>,
'id': 2,
'name': 'MyProduct',
'created_on': datetime.date(2020, 1, 24)}
In [14]: serializer.data
Out[14]: {'name': 'MyProduct', 'created_on': OrderedDict([('year', 2020), ('month', 1), ('day', 24)])}
想通了,我需要在请求中设置 content_type=application/json
header。否则它默认为 content_type=multipart/form-data
将有效载荷展平为 {'name': ['MyProduct'], 'created_on': ['year', 'month', 'day']}
.
为什么搞得这么复杂。你可以做到
class Product:
name = models.CharField(max_length=255, unique=True)
created_on = models.DateField()
然后是序列化器
class ProductSerializer(serialzers.ModelSerializer):
def to_representation(self, instance):
try:
data = super().to_representation(instance)
created_on = {}
### You should check on the syntax for this to get the right value
created_on['year'] = data['created_on'].year
created_on['month'] = data['created_on'].month
created_on['day'] = data['created_on'].day
data['created_on'] = created_on
except :
pass
return data
class Meta:
model = Friend
fields = ("name", "created_on")
或者这样:
class ProductSerializer(serialzers.ModelSerializer):
created_on_2 = serializers.SerializerMethodField()
def get_created_on_2(self, obj):
created_on = {}
### You should check on the syntax for this to get the right value
created_on['year'] = data['created_on'].year
created_on['month'] = data['created_on'].month
created_on['day'] = data['created_on'].day
return created_on
class Meta:
model = Friend
fields = ("name", "created_on", "created_on_2)
这样您仍然可以使用“created_on”的常规日期字符串值发出 POST 请求,并获得您想要的输出
有关详细信息,请查看此 to_respresentation() SerializerMethodField
假设我有简单的 Product
Django 模型:
class Product:
name = models.CharField(max_length=255, unique=True)
created_on = models.DateField()
我正在使用 Django Rest Framework 序列化此模型。我想将 created_on
分解成它自己的对象(包括 GET 请求的响应和 POST 请求中的有效负载):
{
"name": "MyProduct",
"created_on": {
"year": 2020,
"month": 1,
"day": 24
}
}
这是我目前的情况:
class DateSerializer(serializers.Serializer):
year = serializers.IntegerField()
month = serializers.IntegerField()
day = serializers.IntegerField()
def validate(data):
return datetime.date(data["year"], data["month"], data["day"])
class ProductSerializer(serialzers.ModelSerializer):
created_on = DateSerializer()
class Meta:
model = Friend
fields = ("name", "created_on")
def create(self, validated_data):
return Product.objects.create(**validated_data)
class ProductViewset(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
这种方法适用于 GET 请求(也就是说,我得到上面的 json)。但是,它不适用于 POST 请求(有效负载是上面的 json)。响应是 400
状态代码和消息 {'created_on': [ErrorDetail(string='This field is required.', code='required')]}
.
如果我将 required=False
传递给 DateSerializer
,我会看到 create
方法中的 self.initial_data
是 <QueryDict: {'name': ['MyProduct'], 'created_on': ['year', 'month', 'day']}>
。所以这些值由于某种原因消失了。
知道我在这里做错了什么以及如何让它工作吗?
class DateSerializer(serializers.Serializer):
year = serializers.IntegerField()
month = serializers.IntegerField()
day = serializers.IntegerField()
def to_internal_value(data):
return datetime.date(data["year"], data["month"], data["day"])
覆盖validate(...)
方法 ProductSerializer
class as,
<b>from datetime import date</b>
class DateSerializer(serializers.Serializer):
year = serializers.IntegerField()
month = serializers.IntegerField()
day = serializers.IntegerField()
class ProductSerializer(serializers.ModelSerializer):
created_on = DateSerializer()
<b>def validate(self, attrs):
super().validate(attrs)
attrs['created_on'] = date(**attrs['created_on'])
return attrs</b>
class Meta:
model = Product
fields = ("name", "created_on")
示例:
In [8]: payload = {"name": "MyProduct", "created_on": {"year": 2020, "month": 1, "day": 24}}
In [9]: serializer = ProductSerializer(data=payload)
In [10]: serializer.is_valid(True)
Out[10]: True
In [11]: serializer.validated_data
Out[11]:
OrderedDict([('name', 'MyProduct'),
('created_on', datetime.date(2020, 1, 24))])
In [12]: product_instance = serializer.save()
In [13]: product_instance.__dict__
Out[13]:
{'_state': <django.db.models.base.ModelState at 0x7f75c0629978>,
'id': 2,
'name': 'MyProduct',
'created_on': datetime.date(2020, 1, 24)}
In [14]: serializer.data
Out[14]: {'name': 'MyProduct', 'created_on': OrderedDict([('year', 2020), ('month', 1), ('day', 24)])}
想通了,我需要在请求中设置 content_type=application/json
header。否则它默认为 content_type=multipart/form-data
将有效载荷展平为 {'name': ['MyProduct'], 'created_on': ['year', 'month', 'day']}
.
为什么搞得这么复杂。你可以做到
class Product:
name = models.CharField(max_length=255, unique=True)
created_on = models.DateField()
然后是序列化器
class ProductSerializer(serialzers.ModelSerializer):
def to_representation(self, instance):
try:
data = super().to_representation(instance)
created_on = {}
### You should check on the syntax for this to get the right value
created_on['year'] = data['created_on'].year
created_on['month'] = data['created_on'].month
created_on['day'] = data['created_on'].day
data['created_on'] = created_on
except :
pass
return data
class Meta:
model = Friend
fields = ("name", "created_on")
或者这样:
class ProductSerializer(serialzers.ModelSerializer):
created_on_2 = serializers.SerializerMethodField()
def get_created_on_2(self, obj):
created_on = {}
### You should check on the syntax for this to get the right value
created_on['year'] = data['created_on'].year
created_on['month'] = data['created_on'].month
created_on['day'] = data['created_on'].day
return created_on
class Meta:
model = Friend
fields = ("name", "created_on", "created_on_2)
这样您仍然可以使用“created_on”的常规日期字符串值发出 POST 请求,并获得您想要的输出 有关详细信息,请查看此 to_respresentation() SerializerMethodField