活动地址:CSDN21天学习挑战赛
当view
继承restframework
的generics.ListAPIView
的接口后,需要定义serializer_class
实现数据的序列化,但是往往我们写业务逻辑时不确定具体的序列化class,这时候据需要根据传递的参数或者路由(url)来动态配置serializer_class
,那么如何动态配置序列化类serializer_class
呢?
get_serializer_class(self)介绍
在restframework的GenericAPIView
类有get_serializer_class(self)
方法,调用get_serializer_class(self)
方法时默认返回设置的serializer_class
序列化类,只要在我们的view中重写get_serializer_class(self)
方法即可实现动态配置serializer_class
。
get_serializer_class(self)
源码如下:
def get_serializer_class(self):
"""
Return the class to use for the serializer.
Defaults to using `self.serializer_class`.
You may want to override this if you need to provide different
serializations depending on the incoming request.
(Eg. admins get full serialization, others get basic serialization)
"""
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
return self.serializer_class
官方文档: https://www.django-rest-framework.org/api-guide/generic-views/#get_serializer_classself
重写get_serializer_class(self)
重写get_serializer_class(self)
方法实现动态配置序列化类,这里需要注意的是如果重写get_serializer_class(self)
一定要返回一个序列化类,如果没有返回一个序列化类即使定义了serializer_class
也会报错。
还有一个问题需要注意,当自定义序列化类后对应的model
也需要根据自定义的序列化类改变,这样在调用self.get_serializer(page, many=True, request=request)
方法后才可以正常序列化数据,但是如何动态获取model
实现查询queryset
呢?
这时候可以通过调用重写的get_serializer_class()
方法获取序列化类,再根据序列化中的Meta
类获取实体类model
,然后实现数据查询。
完整的代码如下:
class Menus(generics.ListAPIView):
renderer_classes = [TemplateHTMLRenderer]
serializer_class = ArticlesSerializer # 定义默认序列化类
pagination_class = Pagination # 定义翻页类(Pagination继承PageNumberPagination重写)
# 重写get_serializer_class(self)实现动态配置serializer_class
def get_serializer_class(self):
menu = self.request.GET.get("menu")
if menu == "categories":
return CategoriesArticlesSerializer
elif menu == "tags":
return TagsArticlesSerializer
else:
return super().get_serializer_class() # 获取父类的get_serializer_class(),也就serializer_class配置的序列化类
def list(self, request):
menu = request.GET.get("menu")
Serializer = self.get_serializer_class() # 获取序列化类
model = Serializer.Meta.model # 根据序列化类获取model
queryset = model.objects.all() # 查询数据queryset
page = self.paginate_queryset(queryset) # 获取分页数据queryset
if page is not None:
serializer = self.get_serializer(page, many=True, request=request) # 实现数据序列化
return self.get_paginated_response({'articles': serializer.data, "template_name": '%s.html' % menu})
serializer = self.get_serializer(instance=queryset, many=True)
return Response({"data": {'articles': serializer.data, template_name='%s.html' % menu)
小结
上面的代码中pagination_class = Pagination
Pagination
类是继承PageNumberPagination
,重写了get_paginated_response
方法,实现页码、总页码、上一页、下一页和总条数等计算和相关message、code信息,这里后面文章也会介绍。
还有此篇文章renderer_classes
渲染器用的Django模板,调用了TemplateHTMLRenderer
,通过定义template_name
实现数据渲染的html,这里由于需要动态调用不同的html,所以把template_name
放在了Response
进行指定,但是这样不够优雅,可以通过重写get_template_names
方法自定义模板界面,这里后面文章也会介绍。
最后通过在实现自定义序列化类,学习了djangorestframework
的GenericAPIView
类源码,看到所有的restframework
的apiview都继承了GenericAPIView
类。djangorestframework
提供了丰富的类视图、Mixin扩展类,简化视图的编写。此篇文档就到这里,后面会逐步对djangorestframework
其他功能进行扩展介绍,包括序列化、反序列化、身份认证和权限认证等,敬请期待。
此篇文章如果对你有帮助,请点赞收藏加关注。如果有疑问可以评论留言哈。