django-rest-framework - 用于 CRUD 的通用 DRF 串行器架构
问题描述
假设我们有一个 Django Rest Framework 端点:
class Comment(models.Model):
article = models.ForeignKey(Article)
author = models.ForeignKey(Author)
content = models.TextField()
class CommentsListCreateView(
mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView
):
allowed_methods = ['GET', 'POST']
serializer_class = CommentSerializer
queryset = Comment.objects.all()
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
我希望端点像这样工作:
- GET 只返回以下格式的评论列表:
[{
article: {id: 1, title: '100 things about'},
author: {id: 1, name: 'Miguel'},
content: 'Blah blah blah'
}]
- POST 创建一个新评论并以相同格式返回新评论的 JSON:
POST {article: 1, author: 1, content: 'Blah blah blah again'}
-->
{
article: {id: 1, title: '100 things about'},
author: {id: 1, name: 'Miguel'},
content: 'Blah blah blah again'
}
请注意,我将 obj ID 作为参数发布,但服务器返回 obj 详细信息。
这种方法好吗?
现在我有两个序列化器 CommentListSerializer 和 CommentCreateSerializer 用于列表和视图,但对我来说看起来很难看。我敢打赌,还有很多其他更好的想法,但如果没有你的帮助,我就无法实现 =) 谢谢。
解决方案
这是一种完全有效的方法,特别是如果您希望客户端无需执行额外请求来检索相关数据,并且服务器无需解析有效负载以提取关系的 ID。
如果我理解正确,您正在寻找更高级的解决方案?在这种情况下,我是否可以提出以下建议:
class ArticleSerializer(ModelSerializer):
class Meta:
model = Article
fields = ["id", "title"]
class AuthorSerializer(ModelSerializer):
class Meta:
model = Author
fields = ["id", "name"]
class CommentSerializer(ModelSerializer):
class Meta:
model = Comment
fields = ["article", "author", "content"]
def to_representation(self, instance):
representation = self.to_representation(instance)
representation.update({
"article": ArticleSerializer(instance.article).data,
"author": AuthorSerializer(instance.author).data
})
return representation
class CommentsListCreateView(ListCreateAPIView):
serializer_class = CommentSerializer
queryset = Comment.objects.all()
我没有运行这段代码,所以可能会有一些错误,但这是一般的想法。我通常更喜欢使用HyperlinkedModelSerializer
,HyperlinkedRelatedField
因此客户端不必自己重建 URL,我会自动将它们解析为实例。这经常导致我继承HyperlinkedRelatedField
和覆盖它的to_representation
方法。这样,我可以将要用于序列化输出的序列化程序作为参数传递。一个粗略的草案如下:
class CustomHyperlinkRelatedField(HyperlinkRelatedField):
self.serializer_class = None
def __init__(self, view_name=None, **kwargs):
self.serializer_class = kwargs.pop(
"serializer_class", self.serializer_class
)
super().__init__(view_name=view_name, **kwargs)
def to_representation(self, instance):
if not self.serializer_class:
return super().to_representation(instance)
obj = get_object_or_404(queryset, pk=instance.pk)
request = self.context["request"]
return self.serializer_class(obj, context={"request": request}).data
class SomeSerializer(Serializer):
relation = CustomHyperlinkedRelatedField(
queryset=SomeModel.objects.all(),
serializer_class=SomeModelSerializer
)
推荐阅读
- android-studio - 使用现有文档创建错误报告并共享
- oracle - SQL 文件未在 Oracle 12C 数据库启动时执行
- python - 检索大型 Firestore 文档的内容
- excel - Web 浏览器控件中的 JavaScript
- typescript - 在 A-Frame 中动态创建的添加事件监听器
- ios - 在项目`Runner.xcodeproj`中找不到名为`Runner`的目标确实找到了`dev`和`prod`
- python - 删除页面重新加载时的数据库异常错误
- python - 在 Azure Functions 中设置 python TimerTrigger 的正确方法?
- mysql - 展开并分组以映射范围内的所有日期
- spring-webflux - spring webflux出错时如何返回错误请求?