serializers序列化器-Model:高级应用
一:source和时间
前置:开始前创建表technicalUser,并添加数据到数据表中
# 技术人员表 class technicalUser(models.Model): db_table = "technicalUser" name = models.CharField(verbose_name="姓名", max_length=32) age = models.IntegerField(verbose_name="年龄") gender = models.SmallIntegerField(verbose_name="性别", choices=((1, "男"), (2, "女"))) depart = models.ForeignKey(verbose_name="部门", to="Depart", on_delete=models.CASCADE) ctime = models.DateTimeField(verbose_name="时间", auto_now_add=True) # 添加表后,配置url # path('api/<str:version>/user/', views.UserView.as_view()) # 配置完成后,视图添加新视图类 class UserView(MyAPIView): def get(self, request, *args, **kwargs): queryset = technicalUser.objects.all() ser = TechnicalUserSerializer(instance=queryset, many=True) return Response(ser.data)
数据库数据
1、在 https://www.cnblogs.com/guanyf/p/18584479中,使用serializers.Serializer创建视图类时,必须手动添加字段,DRF为方便创建模型类,提供了ModelSerializer类
class DepartSerializer(serializers.ModelSerializer): class Meta: model = Depart fields = "__all__" # 内部类必须使用Meta,model和fields为死格式,不能改变,这是DRF限制 # 接口返回 [ { "id": 1, "name": "张三", "age": 18, "gender": 1, "ctime": "2024-12-04T17:37:40+08:00", "depart": 1 }, { "id": 2, "name": "李四", "age": 19, "gender": 2, "ctime": "2024-12-04T17:38:26+08:00", "depart": 2 } ]
2、当需要指定返回字段时,可以使用fields进行指定
class TechnicalUserSerializer(serializers.ModelSerializer): class Meta: model = technicalUser fields = ["name", "age", "gender"] # 指定后,访问接口时,将显示指定的字段 # 接口返回 [ { "name": "张三", "age": 18, "gender": 1 }, { "name": "李四", "age": 19, "gender": 2 } ]
3、访问接口时,gender字段显示为1或者2,可以通过source="get_gender_display"显示配置的性别
class TechnicalUserSerializer(serializers.ModelSerializer): gender = serializers.CharField(source="get_gender_display") class Meta: model = technicalUser fields = ["name", "age", "gender"] # 接口返回 [ { "name": "张三", "age": 18, "gender": "男" }, { "name": "李四", "age": 19, "gender": "女" } ]
3、通过ForeignKey获取相关联的数据
class TechnicalUserSerializer(serializers.ModelSerializer): gender = serializers.CharField(source="get_gender_display") # 当有多个数据时,可连续调用 如 source="depart.title.xx.xx.xx depart = serializers.CharField(source="depart.title") class Meta: model = technicalUser fields = ["name", "age", "gender", "depart"] # 接口返回 [ { "name": "张三", "age": 18, "gender": "男", "depart": "技术部" }, { "name": "李四", "age": 19, "gender": "女", "depart": "工程部" } ]
4、返回citme时间字段,可以通过format进行指定返回格式
class TechnicalUserSerializer(serializers.ModelSerializer): gender = serializers.CharField(source="get_gender_display") depart = serializers.CharField(source="depart.title") ctime = serializers.DateTimeField(format="%Y-%m-%d") class Meta: model = technicalUser fields = ["name", "age", "gender", "depart", "ctime"] # 接口返回 [ { "name": "张三", "age": 18, "gender": "男", "depart": "技术部", "ctime": "2024-12-04" }, { "name": "李四", "age": 19, "gender": "女", "depart": "工程部", "ctime": "2024-12-04" } ]
二,自定义方法
如果想要返回自定义的值,可以通过SerializerMethodField进行定义
class TechnicalUserSerializer(serializers.ModelSerializer): gender = serializers.CharField(source="get_gender_display") depart = serializers.CharField(source="depart.title") ctime = serializers.DateTimeField(format="%Y-%m-%d") # 自定义字段 xxx = serializers.SerializerMethodField() class Meta: model = technicalUser fields = ["name", "age", "gender", "depart", "ctime", "xxx"]
定义了xxx时,自动触发get_xxx方法
class TechnicalUserSerializer(serializers.ModelSerializer): gender = serializers.CharField(source="get_gender_display") depart = serializers.CharField(source="depart.title") ctime = serializers.DateTimeField(format="%Y-%m-%d") # 自定义字段 xxx = serializers.SerializerMethodField() # 自定义字段方法 # 运行原理:当序列化时,循环获取queryset或数据对象的相关字段,当运行到xxx时,在数据库中没有找到相关字段,自动触发get_xxx方法,执行get_xxx方法时,将当前对象作为参数传递给get_xxx,也就是 obj def get_xxx(self, obj): return 'xxx' class Meta: model = technicalUser fields = ["name", "age", "gender", "depart", "ctime", "xxx"] # 接口返回 [ { "name": "张三", "age": 18, "gender": "男", "depart": "技术部", "ctime": "2024-12-04", "xxx": "xxx" }, { "name": "李四", "age": 19, "gender": "女", "depart": "工程部", "ctime": "2024-12-04", "xxx": "xxx" } ] # 通过<运行原理>我们知道obj是当前对象,那么通过obj可以调用当前对象的每个字段,修改get_xxx方法 # 自定义字段方法 def get_xxx(self, obj): # obj.name 获取每个对象的name值 return "{}-{}-{}".format(obj.name, obj.age, obj.ctime) # 接口返回 [ { "name": "张三", "age": 18, "gender": "男", "depart": "技术部", "ctime": "2024-12-04", "xxx": "张三-18-2024-12-04 09:37:40+00:00" }, { "name": "李四", "age": 19, "gender": "女", "depart": "工程部", "ctime": "2024-12-04", "xxx": "李四-19-2024-12-04 09:38:26+00:00" } ]
三,嵌套
前置:新建表tag,并添加数据
class Tag(models.Model): db_table = "tag" caption = models.CharField(verbose_name="标签", max_length=32)
修改技术人员表添加ManyToMany字段
# 技术人员表 class technicalUser(models.Model): db_table = "technicalUser" name = models.CharField(verbose_name="姓名", max_length=32) age = models.IntegerField(verbose_name="年龄") gender = models.SmallIntegerField(verbose_name="性别", choices=((1, "男"), (2, "女"))) depart = models.ForeignKey(verbose_name="部门", to="Depart", on_delete=models.CASCADE) ctime = models.DateTimeField(verbose_name="时间", auto_now_add=True) # 添加ManyToMany字段 tags = models.ManyToManyField(verbose_name="标签", to="Tag")
问题:怎么获取人员的标签信息?
方式1:通过自定义方法获取用户的全部标签
# 自定义字段方法 def get_xxx(self, obj): queryset = obj.tags.all() tag_list = [{"id": tag.id, "caption": tag.caption} for tag in queryset] return tag_list # 接口返回 [ { "name": "张三", "age": 18, "gender": "男", "depart": "技术部", "ctime": "2024-12-04", "xxx": [ { "id": 1, "caption": "java程序员" }, { "id": 2, "caption": "go程序员" } ] }, { "name": "李四", "age": 19, "gender": "女", "depart": "工程部", "ctime": "2024-12-04", "xxx": [ { "id": 2, "caption": "go程序员" } ] } ]
方式二:通过嵌套的方式<针对fk<ForeignKey>和m2m<:ManyToManyField>>
1、添加tag的序列化类
class TagSerializer(serializers.ModelSerializer): class Meta: model = Tag fields = "__all__"
2、如果没有Depart的序列化类,添加序列化器类
class DepartSerializer(serializers.ModelSerializer): class Meta: model = Depart fields = "__all__"
3、修改TechnicalUserSerializer类
class TechnicalUserSerializer(serializers.ModelSerializer): gender = serializers.CharField(source="get_gender_display") # depart = serializers.CharField(source="depart.title") depart = DepartSerializer() # 引用DepartSerializer # 引用TagSerializer # 注意当tags包含一个或多个对象时,加上many=True,否则报错AttributeError, 命名时,必须与数据库保持一致,如 tags = TagSerializer ,必须叫tags
tags = TagSerializer(many=True) ctime = serializers.DateTimeField(format="%Y-%m-%d") # 自定义字段 # xxx = serializers.SerializerMethodField() # 自定义字段方法 # def get_xxx(self, obj): # queryset = obj.tags.all() # tag_list = [{"id": tag.id, "caption": tag.caption} for tag in queryset] # return tag_list class Meta: model = technicalUser fields = ["name", "age", "gender", "depart", "ctime", "tags"] # 返回接口,返回数据与方式一返回的数据一致 [ { "name": "张三", "age": 18, "gender": "男", "depart": { "id": 1, "title": "技术部", "order": 1, "count": 10 }, "ctime": "2024-12-04", "tags": [ { "id": 1, "caption": "java程序员" }, { "id": 2, "caption": "go程序员" } ] }, { "name": "李四", "age": 19, "gender": "女", "depart": { "id": 2, "title": "工程部", "order": 2, "count": 20 }, "ctime": "2024-12-04", "tags": [ { "id": 2, "caption": "go程序员" } ] } ]