Django restframework序列化数据的基本使用
本篇文章以角色、用户、组三表为例,用户和角色是多对多的关系,用户和组是多对一的关系。关联时使用对方表的id,每张表至少有两个字段:id和name
class Group(models.Model): name = models.CharField(max_length=50) class Role(models.Model): name = models.CharField(max_length=50) class User(models.Model): user_type_choice = ( (1, "普通用户"), (2, "VIP"), (3, "SVIP") ) name = models.CharField(max_length=50) user_type = models.IntegerField(choices=user_type_choice) group = models.ForeignKey("Group", on_delete=models.CASCADE) roles = model.ManyToManyField("Roles")
1、不使用序列化器时,响应数据的方式:将QuerySet数据转化为list列表,再使用json.dumps()转化为json格式,下面代码是无序列化器对象的请求视图类
import json class UserView(APIView): def get(self, request): users = User.object.all() # 将QuerySet集合数据转化为list集合数据 users = list(users) data = json.dumps(users) # 数据响应 return HttpResponse(data)
2、有序列化器时,序列化单表的数据(可能是QuerySet数据,也可能是单个对象的数据)这里序列化用户表的部分数据,自定义一个序列化类就需要继承序列化类(先继承Serializer类)。在序列化字段时是有两种方式:第一种是序列化类的变量名必须和模型类的变量名一样;第二种是序列化类的变量名可以随意,但是Field参数必须有source变量和值,这个就要和模型类的变量名称一样。另外在定义序列化对象时,如果返回的数据是QuerySet集合,序列化类传的参数many值未True;如果返回的是单个对象,many参数值未False,而且也不用json.dumps(),直接响应序列化对象点data即可。
class UserSerializer(serializers.Serializer): # 第一种序列化方式 id = serializers.IntegerField() # 第二种序列化方式 username = serializers.CharField(source="name") # 第二种方式的choices表达 current_type = serializers.CharField(source="get_user_type_display") class UserView(APIView): def get(self, request): users = User.object.all() ser = UserSerializer(instance=users, many=True) data = json.dumps(ser.data) return HttpResponse(data)
3、如果是两个或者多个表一起序列化数据时,如显示当前用户所在的组的名称,或者是显示当前用户下的所有角色信息。上面字段参数source可以直接点的格式查询对象下的数据,就比如是用户所在组的名称;当然也可以使用自定义返回值的字段类SerializerMethodField(),这时还需要定义一个以get_开头、变量名称结尾的方法,方法参数self和row,row表示当前变量的对象。请求视图类可以不变,主要是序列化不同。
class UserSerializer(serializers.Serializer): # 第一种序列化方式 id = serializers.IntegerField() # 第二种序列化方式 username = serializers.CharField(source="name") # 第二种方式的choices表达 current_type = serializers.CharField(source="get_user_type_display") # 通过点的方式显示所在组的名称 group_name = serializers.CharField(source="group.name") # 通过自定义方法返回字段的值 roles = serializers.SerializerMethodField() def get_roles(self, row): role_list = row.object.all() data = [] for item in role_list: data.append({"id":item.id, "name":item.name}) return data
4、在自定义序列化类时,还可以继承另一个序列化类ModelSerializer,之前的Serializer类的序列方式都支持;还可以在自定义序列化类的内部定义一个内部类,指定model,和fields字段就可以简化之前的前两种序列化方式的写法,第3步中的两个需求,只需要在内部类中写一行代码即可解决depth = 1,但是这一行代码不能滥用,只有1~10之间使用可方便,超过10,这样返回的速度就会显得特别慢。depth的意思就是搜寻的对象下是否还有其他对象,这其他对象下又有其他对象,以此类推下去就表示一层一层。
class UserSerializer(serializers.ModelSerializer): group_name = serializers.CharField(source="group.name") roles = serializers.SerializerMethodField() class Meta: model = User # 所有字段(包括组和角色) # fields = "__all__" # 部分字段 fields = ["id", "name", "group_name", "roles"] def get_roles(self, row): role_list = row.object.all() data = [] for item in role_list: data.append({"id": item.id, "name":item.name}) return data
5、有些时候可能会存在另一种需求,如当前用户所在组的信息,所在组的信息是一个url地址。完成这一需求需要在请求视图类的请求方法的序列化对象的参数中增加一个参数和值:context = {"request": request},自定义的序列化类中变量名称的值参数view_name是urls.py对应视图函数的名称,lookup_field是模型类变量的名称,lookup_url_field是路由url路径上的地址,不是get参数中的地址。
class UserSerializer(serializers.ModelSerializer): # 对应的url路由:url(r"group/?P<my_id>/", views.GroupView.as_view(), name="group") group = serializers.HyperlinkedIdentityField(view_name="group", lookup_field="group_id", lookup_url_field="my_id") roles = serializers.SerializerMethodField() class Meta: model = User # 所有字段(包括组和角色) # fields = "__all__" # 部分字段 fields = ["id", "name", "group", "roles"] def get_roles(self, row): role_list = row.object.all() data = [] for item in role_list: data.append({"id": item.id, "name":item.name}) return data class UserView(APIView): def get(self, request): user = User.object.all() ser = UserSerializer(instance=user, mant=True, context={"request":request} data = json.dumps(ser.data) return HttpResponse(data)