Django REST Framework实现动态序列化数据及动态分配权限
动态序列化
在django RESTful API开发中,由于前后端json数据的交互,设计到大量的序列化和反序列化操作,好在DRF给我们提供了强大的序列化功能,解决了这一问题。但是,当涉及到单api实现多个功能的时候,很多情况下,我们希望同一个API接口,在处理不同场景的时候,返回不一样的序列化数据.
好在,DRF提供了一个viewset类,这个类在重载了基视图类View的as_view的基础上,还添加了initialize_request函数,这个函数可以捕捉request类型,并返回对应的action。
然后在通过分析serializer源码后,总结了下面动态序列化方法,举例做说明。
实例:这里以在淘宝收藏商铺店家过程和在个人中心查看收藏了那些店家两个场景作为分配对象。
1. 正常情况下,当用户进入个人中心查看收藏的时候,其实是向后台发送get请求,在DRF中,这是个list操作,用户希望返回所有的收藏,并且在展示页面,我们还希望,能够看到该店,销量最好的产品,以及该店的信誉值,这时候我们得通过嵌套序列化的形式,将store序列化加到我们store字段里面来,具体程序如下:
class UserFavDetailSerializer(serializers.ModelSerializer):
"""
user fav exhibition
"""
store = StoresSerializer()
class Meta:
model = UserFav
fields = ("store","id")
2 . 但是,当用户去添加收藏的时候,也就是说,对具体某一个商店,添加收藏,这时候执行的是一个POST的请求,如果继续使用上面的序列化,然后在view里面执行create的时候后台保存的,其实是整个商店所有的数据,这对数据库的存储压力是很大的。所以,需要定义一个新的序列化类.
此外,后台得判断用户是否收藏这个店家,如果收藏,就弹出提醒,”已经收藏”,然后执行取消收藏操作,并且,还得验证是否用户登陆,之前查看收藏,是用户登陆的前提下,才能进入到用户中心,然后才能去查看收藏。现在需要验证,就得序列化user字段,具体程序如下:
class UserFavSerializer(serializers.ModelSerializer):
"""
user fav serializer
"""
# configure the current user as the post user to the frontend
user = serializers.HiddenField(
default=serializers.CurrentUserDefault())
class Meta:
model = UserFav
validators = [
# unite unique query
UniqueTogetherValidator(
queryset=UserFav.objects.all(),
fields=('user', 'store'),
message="已经收藏"
)]
fields = ("user", "store", "id")
当然,这里面还进行了联合唯一查询,也就是一个店家只能被一个用户收藏一次。
现在我们已经定义了两个序列化类,但是,如何去具体分配这两个序列化呢?这就涉及到DRF执行serializer的原理了,在查究源码后,我们得到,其实在源码底层,是通过 genericApiview中定义get_serializer函数去实现序列化类实例化,并且在modelview类中进行validate,所以我们只要重写获得get_serializer方法,动态的获取序列化类,再view视图类中定义类如下:
if self.action == "list":
return UserFavDetailSerializer
elif self.action == "create":
return UserFavSerializer
return UserFavSerializer
通过viewset返回的action,来确认,接口传来的请求,是要查看还是要添加,然后返回具体的序列化数据,这样,我们就实现了动态的serializer
动态权限要求
与动态的序列化相同,直接上实例。
实例:用户注册和查看用户详情信息
做过开发的朋友可能就知道,其实这两个是一个接口,都是一个use的API,知识根据不同的请求,返回不同的数据。场景是,当用户注册的时候,我们对用户的权限,是没有要求的,但是,当用户要查看个人中心详情信息的时候,我们要先确认用户已经登陆了的,没登陆是不能让查看的.
问题分析了,那就很简单,用户注册的时候,我们对用户权限要求,返回空,对查看用户详情的时候,我们赋予具体的权限要求,分析源码后,发现获取权限的get_premissons函数,所以只要设置以下代码到你的view视图里面:
def get_permissions(self):
"""
over get_permission method .realize dynastic serializer
create -- 无权限要求
get -- 登陆认证权限要求
others -- 暂时无权限要求
"""
# 只有继承自ViewsetMixin类的视图类才拥有action属性
if self.action == "retrieve":
return [permissions.IsAuthenticated()]
elif self.action == "create":
return []
return []
permissions.IsAuthenticated()是我自定义的用户认证方法,
这样就是实现了动态的权限要求
总结:
动态的序列化和权限要求,都是通过一个接口去满足多种要求,只定义一个view视图类,去实现这些功能,代码的重用性更高,代码量也有所减少。