Django Rest Framework:反序列化并从 validated_data 获取主键
Django Rest Framework: Deserializing and get the primary key from validated_data
我定义了一个嵌套模型 Product
如下。每个 Product
可以属于很多 Productlist
.
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
product_name = models.CharField(max_length=50)
class Productlist(models.Model):
productlist_id = models.AutoField(primary_key=True)
productlist_name = models.CharField(max_length=50)
product = models.ManyToManyField(Product, related_name='productlists')
对应的序列化器是:
class ProductlistSerializer(serializers.ModelSerializer):
class Meta:
model = Productlist
fields = ('productlist_id', 'productlist_name',)
class ProductSerializer(serializers.ModelSerializer):
productlists = ProductlistSerializer(many=True, required=False)
class Meta:
model = Product
fields = ('product_id', 'product_name', 'product lists')
def create(self, validated_data):
#some codes
当我 POST
一个新的 Product
(url(r'^api/products/$', views.ProductEnum.as_view()
) 时,我想更新产品列表以将新产品添加到相应的产品列表中。我更喜欢使用的 JSON 文件是:
{
"product_name": "product1"
"productlist": [
{
"productlist_id": 1,
"productlist_name": "list1",
},
{
"productlist_id": 2,
"productlist_name": list2"
}
]
}
问题是我无法从 validated_data
获取 productlist_id
。在 Django Rest Framework 中,你总是需要调用 to_internal_value()
来反序列化数据并生成 validated_data
。经过一些调试后,我检查了 DRF
的代码并在 to_internal_value()
中找到了以下片段:
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
if not isinstance(data, dict):
message = self.error_messages['invalid'].format(
datatype=type(data).__name__
)
raise ValidationError({
api_settings.NON_FIELD_ERRORS_KEY: [message]
})
ret = OrderedDict()
errors = OrderedDict()
fields = [
field for field in self.fields.values()
if (not field.read_only) or (field.default is not empty)
]
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = list(exc.messages)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
请注意 to_internal_value
的字段忽略了 IntegerField(read_only=True)
因为它不能满足以下条件:
fields = [
field for field in self.fields.values()
if (not field.read_only) or (field.default is not empty)
]
所以 validated_data
将只有以下数据:
{
"product_name": "product1"
"productlist": [
{
"productlist_name": "list1",
},
{
"productlist_name": list2"
}
]
}
如何获取产品列表的主键?提前致谢!
经过一番挖掘,我发现 read_only
字段仅用于输出表示。您可以在 Django REST Framework
.
的官方 github link 上找到类似的问题
所以解决方案是覆盖序列化程序中的 read_only
字段,如下所示:
class ProductlistSerializer(serializers.ModelSerializer):
productlist_id = serializers.IntegerField(read_only=False)
class Meta:
model = Productlist
fields = ('productlist_id', 'productlist_name',)
我定义了一个嵌套模型 Product
如下。每个 Product
可以属于很多 Productlist
.
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
product_name = models.CharField(max_length=50)
class Productlist(models.Model):
productlist_id = models.AutoField(primary_key=True)
productlist_name = models.CharField(max_length=50)
product = models.ManyToManyField(Product, related_name='productlists')
对应的序列化器是:
class ProductlistSerializer(serializers.ModelSerializer):
class Meta:
model = Productlist
fields = ('productlist_id', 'productlist_name',)
class ProductSerializer(serializers.ModelSerializer):
productlists = ProductlistSerializer(many=True, required=False)
class Meta:
model = Product
fields = ('product_id', 'product_name', 'product lists')
def create(self, validated_data):
#some codes
当我 POST
一个新的 Product
(url(r'^api/products/$', views.ProductEnum.as_view()
) 时,我想更新产品列表以将新产品添加到相应的产品列表中。我更喜欢使用的 JSON 文件是:
{
"product_name": "product1"
"productlist": [
{
"productlist_id": 1,
"productlist_name": "list1",
},
{
"productlist_id": 2,
"productlist_name": list2"
}
]
}
问题是我无法从 validated_data
获取 productlist_id
。在 Django Rest Framework 中,你总是需要调用 to_internal_value()
来反序列化数据并生成 validated_data
。经过一些调试后,我检查了 DRF
的代码并在 to_internal_value()
中找到了以下片段:
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
if not isinstance(data, dict):
message = self.error_messages['invalid'].format(
datatype=type(data).__name__
)
raise ValidationError({
api_settings.NON_FIELD_ERRORS_KEY: [message]
})
ret = OrderedDict()
errors = OrderedDict()
fields = [
field for field in self.fields.values()
if (not field.read_only) or (field.default is not empty)
]
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = list(exc.messages)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
请注意 to_internal_value
的字段忽略了 IntegerField(read_only=True)
因为它不能满足以下条件:
fields = [
field for field in self.fields.values()
if (not field.read_only) or (field.default is not empty)
]
所以 validated_data
将只有以下数据:
{
"product_name": "product1"
"productlist": [
{
"productlist_name": "list1",
},
{
"productlist_name": list2"
}
]
}
如何获取产品列表的主键?提前致谢!
经过一番挖掘,我发现 read_only
字段仅用于输出表示。您可以在 Django REST Framework
.
所以解决方案是覆盖序列化程序中的 read_only
字段,如下所示:
class ProductlistSerializer(serializers.ModelSerializer):
productlist_id = serializers.IntegerField(read_only=False)
class Meta:
model = Productlist
fields = ('productlist_id', 'productlist_name',)