我有一个rest_framework.ViewSet
使用内联序列化器(BarSerializer)来显示我的Bar模型以及我的Foo模型。
class FooSerializer(serializers.ModelSerializer):
bar = BarSerializer()
class Meta:
model = Foo
fields = ("name", "bar")
对/api/foos/1/
的调用会返回:
{
"bar": {"name": "bar", "number": 1},
"name": "up"
}
但是,我想创建一个带有由foreignkey引用的Bars的新Foos。
POST到/api/foos/
会创建一个新的Foo。
{
"bar": 1,
"name": "up"
}
使用标准ViewSet似乎是不可能的。在理想的世界中,我使用ForeignKey进行POST并获得“内联”模型。
目前我正在覆盖get_serializer_class
和create methods
以返回每个请求的不同序列化程序。由于这似乎是一个相当常见的用例,我有什么遗漏吗?
答案 0 :(得分:1)
使用以下代码段,您可以将PK值序列化为所需数据,而保存时您只能提供PK值
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.utils.encoding import smart_text
from rest_framework import serializers
class CustomRelatedField(serializers.RelatedField):
"""
Represents a primary key relationship with {'pk':1,'name': 'foo'}
"""
read_only = False
default_error_messages = {
'does_not_exist': ("Invalid pk '%s' - object does not exist."),
'incorrect_type': ('Incorrect type. Expected {"id": 1} format , received %s.'),
}
def __init__(self, *args, **kwargs):
self.fields = kwargs.pop('fields', ('id',))
return super(CustomRelatedField, self).__init__(*args, **kwargs)
def to_native(self, obj):
data = {'id':obj.pk}
for field in self.fields:
value = getattr(obj, field)
data[field] = value
return data
def from_native(self, data):
if isinstance(data, int):
data = {'id':data}
if not isinstance(data, dict):
received = type(data).__name__
msg = self.error_messages['incorrect_type'] % received
raise ValidationError(msg)
if self.queryset is None:
raise Exception('Writable related fields must include a `queryset` argument')
try:
return self.queryset.get(pk=data.get('id'))
except ObjectDoesNotExist:
msg = self.error_messages['does_not_exist'] % smart_text(data)
raise ValidationError(msg)
except (TypeError, ValueError):
received = type(data).__name__
msg = self.error_messages['incorrect_type'] % received
raise ValidationError(msg)
和
class FooSerializer(serializers.ModelSerializer):
bar = CustomRelatedField(fields=('id','name', 'number'))
class Meta:
model = Foo
fields = ("name", "bar")