我想发布一个新的嵌套对象,问题只需要创建一个“顶”对象(播放列表),但不创建“ChannelItem” ...
我的模型:
class Playlist(models.Model):
provider = models.IntegerField()
channel_id = models.CharField(max_length=100)
channel_version = models.CharField(blank=True, max_length=100)
start = models.DateTimeField()
url = models.CharField(max_length=500)
class ChannelItem(models.Model):
playlist = models.ForeignKey(Playlist, editable=False, related_name='channelitems')
content_id = models.CharField(max_length=100)
content_version = models.CharField(blank=True, max_length=100)
我的串行:
class ChannelItemSerializer(serializers.ModelSerializer):
class Meta:
model = ChannelItem
fields = ('content_id', 'content_version')
exclude = ('id')
depth = 1
class PlaylistSerializer(serializers.ModelSerializer):
class Meta:
model = Playlist
fields = ('id', 'provider', 'channel_id', 'channel_version', 'start',
'url', 'channelitems')
depth = 2
channelitems = ChannelItemSerializer()
我使用curl发布以下数据:
'{"provider":125,"channel_id":"xyz", "channel_version":"xsqt",
"start":"2012-12-17T11:04:35","url":"http://192.168.1.83:8080/maaaaa",
"channelitems":[{"content_id":"0.flv", "content_version":"ss"},
{"content_id":"1.flv","content_version":"ss"}]}' http://localhost:8000/playlist_scheduler/playlists/
我收到消息:
HTTP/1.1 201 CREATED
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 17 Dec 2012 20:12:54 GMT
Server: 0.0.0.0
{"id": 25, "provider": 125, "channel_id": "xyz", "channel_version": "xsqt",
"start":"2012-12-17T11:04:35", "url": "http://localhost:8080/something",
"channelitems": []}
嵌套表示目前不支持读写 ,而应是只读的。
你或许应该考虑使用一个平面表示相反,使用PK或超链接关系。
如果您需要嵌套表示,你可能要考虑有两个独立的终点 - 一台可写端点,和嵌套只读端点。
如果有人需要为一个快速和肮脏的解决方案,我想出了这个,我会使用一个项目是暂时的:
class NestedManyToManyField(serializers.WritableField):
def to_native(self, value):
serializer = self.Meta.serializer(value.all(), many=True, context=self.context)
return serializer.data
def from_native(self, data):
serializer = self.Meta.serializer(data=data, many=True, context=self.context)
serializer.is_valid()
serializer.save()
return serializer.object
class Meta:
serializer = None
然后创建自己的子类NestedManyToManyField
:
class TopicNestedSerializer(NestedManyToManyField):
class Meta:
serializer = MyOriginalSerializer
的一个例子MyOriginalSerializer
:
class MyOriginalSerializer(serializers.ModelSerializer):
class Meta:
model = models.MyModel
fields = ('id', 'title',)
这对我来说工作正常为止。 但要注意有干净的修复来:
- https://github.com/tomchristie/django-rest-framework/issues/960
- https://github.com/tomchristie/django-rest-framework/pull/817
之后我做了funcinasse第一版本的长期努力。我相信,随着一些改进可以列入ModelSerializer内
class ChannelItemSerializer(serializers.ModelSerializer):
class Meta:
model = ChannelItem
fields = ('id', 'content_id', 'content_version')
def field_from_native(self, data, files, field_name, into):
try:
if self._use_files:
_files = files[field_name]
else:
_data = data[field_name]
except KeyError:
if getattr(self, 'default', None):
_data = self.default
else:
if getattr(self, 'required', None):
raise ValidationError(self.error_messages['required'])
return
if type(_data) is list:
into[field_name] = []
for item in _data:
into[field_name].append(self._custom_from_native(item))
else:
into[field_name] = self._custom_from_native(_data)
def _custom_from_native(self, data):
self._errors = {}
if data is not None:
attrs = self.restore_fields(data, None)
attrs = self.perform_validation(attrs)
else:
self._errors['non_field_errors'] = ['No input provided']
if not self._errors:
return self.restore_object(attrs, instance=getattr(self, 'object', None))
class PlaylistSerializer(serializers.ModelSerializer):
class Meta:
model = Playlist
fields = ('id', 'provider', 'channel_id', 'channel_version', 'start', 'url', 'channel_items')
depth = 1
channel_items = ChannelItemSerializer()
def restore_object(self, attrs, instance=None):
self.foreign_data = {}
for (obj, model) in self.opts.model._meta.get_all_related_objects_with_model():
field_name = obj.field.related_query_name()
if field_name in attrs:
self.foreign_data[field_name] = attrs.pop(field_name)
return super(PlaylistSerializer, self).restore_object(attrs, instance)
def save(self, save_m2m=True):
super(PlaylistSerializer, self).save(save_m2m)
if getattr(self, 'foreign_data', None):
for accessor_name, object_list in self.foreign_data.items():
setattr(self.object, accessor_name, object_list)
self.foreign_data = {}
return self.object
对于我来说,我有一个混合的解决办法,我是用确定。 即,创建具有一个视图:
- 在其未嵌套串行形式的多对多字段
- 别名嵌套多对多字段与可变
_objs
作为后缀并将其指定为只读 - 当你
PUT
回服务器调和两个别名域和结果存储在未嵌套串行场
如
class MSerializer(serializers.HyperlinkedModelSerializer):
foo_objs = TempSensorSerializer(source='foos', many=True, allow_add_remove=True,required=False,read_only=True)
class Meta:
model = M
fields = ('url', 'foos', 'foo_objs')
我不喜欢这个解决办法,但它打败试图单独查询和检索初始容器后整理嵌套领域。