如果一个 Model 中存在与其他 Model 的关系字段,则 DRF 的 serializer 有两种方式为它们进行序列化:
rest_framework.serializer
中的RelatedField,如 PrimaryKeyRelatedField 以及 HyperlinkRelatedFieldRelatedField 的共同之处是使用某种标识符来指向所关联的 Model 的实例,而几乎不涉及关联的实例本身的信息( SlugRelatedField 除外,但文档中也指出 Slug Field 最好指定 unique=True,因而某种意义上也是标识符)。而 Nested Representation 则是将所关联的实例的部分甚至全部信息也序列化并输出。
这两种方式各有优缺点。使用 RelatedField 无法得到所关联的对象的信息,如果需要这些信息,前端就需要额外发起请求,带来不必要的连接开销,但优势在于 PrimaryKeyRelatedField/SlugRelatedField/HyperlinkedRelatedField 默认都是 read-write 的。如果创建的 Serializer 需要承担更新、创建新对象等写操作,可以省去大量代码。Nested Representation 能获取到所关联对象的完整信息,便于前端进行数据展示,但 Nested Representation 默认是 ReadOnly 的,如果需要它承担写操作,必须自行编写 create 和 update 方法,这将会带来很多不必要的代码量。
因此我现在的解决方案是对同一个 Model 的读和写操作分别创建不同的 Serializer,读操作使用 Nested Representation,写操作使用 PrimaryKeyRelatedField。
请问我的理解与做法是否有什么问题?是否有其他的最佳实践呢?非常感谢!
1
shyz 2019-08-15 18:35:13 +08:00
drf serializer 序列化不是可以关联序列化吗,可以直接关联相关模型类的序列化器
|
2
fourstring OP @shyz #1 是的,Nested Representation 就是这种模式,但是文档指出这种模式必须手动创建 create 和 update 方法,否则不能用于直接的写操作。但是如果在创建和更新模型对象时没有特殊操作的话,这些代码都是高度重复的,会带来大量的冗余代码。相关部分在这里: https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers
|
3
bnm965321 2019-08-16 10:20:00 +08:00 2
没有最佳实践,这也是 RESTful 的不足之处。
按照 RESTful 的定义,应该所有接口都使用 PrimaryKeyRelatedField 或者 HyperlinkRelatedField,但是现实中一些情况下是需要妥协的,一些资源需要改写成 Nested Representation 模式。如果你就单单把数据表映射给前端,就等着被喷吧。 但是什么时候使用 Nested 模式,要根据情况判断。比如一个 article 的 tags,一般不应该让前端去单独请求。 还有个究极办法,是使用 GraphQL。 |
4
bnm965321 2019-08-16 10:22:07 +08:00 1
类似的问题知乎也是有的: https://www.zhihu.com/question/337844933
|
5
freakxx 2019-10-01 11:07:22 +08:00
@fourstring
突然翻到这主题 这个是可以读写一致的,并且可以打开字段, 我之前写过几个版本的这玩意。 还写过递归的版本,反 Nested 存储到复层。 --------------- 从源代码角度来说,serializer 也是一个 field, 你继承 PrimaryKeyRelatedField ( HyperlinkRelatedField )后改写他的 to_internal_value 和 to_representation,就可以实现了你的需求。 字段调用大概长这样子 items = ObjectRelatedField( ... serializer_class=ControlItemSerializer ) 实际上就是丢一个渲染的 serializer 进去 to_representation。 |