前戏

在之前我们写序列化器的时候,写的很low,遇到反序列化的有时候还需要重写该字段,用post请求的时候,还要重写create方法,用put请求的时候,还需要重写update方法。总而言之,写起来很麻烦。来看看之前的是怎么写的

class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False) # 只序列化,不走校验
title = serializers.CharField(max_length=32, validators=[my_validate])
pub_time = serializers.DateField()
category = serializers.CharField(source="get_category_display", read_only=True) # 只序列化用
# 因为前端传的是数字,所以需要重写
post_category = serializers.IntegerField(write_only=True) # 只反序列化用 publisher = PublisherSerializer(read_only=True) # 一对多的表 只序列化用
authors = AuthorSerializer(many=True, read_only=True) # 多对多的表需要指定many=True 只序列化用 publisher_id = serializers.IntegerField(write_only=True) # 只反序列化用
author_list = serializers.ListField(write_only=True) # 只反序列化用 def create(self, validated_data):
# validated_data校验通过的数据
# 通过ORM操作给book表增加数据
book_obj = Book.objects.create(title=validated_data['title'],
pub_time=validated_data['pub_time'],
category=validated_data['post_category'],
publisher_id=validated_data['publisher_id'])
book_obj.authors.add(*validated_data['author_list']) # 这个参数可能是一个列表
return book_obj def update(self, instance, validated_data):
# instance 更新的book_obj对象
# validated_data 校验通过的数据
instance.title = validated_data.get("title",instance.title)
instance.pub_time = validated_data.get("pub_time",instance.pub_time)
instance.category = validated_data.get("post_category",instance.category)
instance.publisher_id = validated_data.get("publisher_id",instance.publisher_id)
if validated_data.get("author_list"): # 可能有多个值
instance.author.set(validated_data["author_list"])
instance.save() # 保存
return instance def validate_title(self, value): # 对单一字段校验
if "BDYJY" not in value.upper():
return value
raise serializers.ValidationError('标题里含有非法字符') # 抛出错误 def validate(self, attrs): # 对多个字段校验
# attrs是一个字典,里面是传过来的所有字段
if 'python' in attrs['title'].lower() and attrs['post_category']==1:
return attrs
else:
raise serializers.ValidationError('传的参数有误,请重新上传')
from django.db import models

# Create your models here.

__all__ = ["Book", "Publisher", "Author"]

class Book(models.Model):
title = models.CharField(max_length=32)
CHOICES = ((1, "python"), (2, "Liunux"), (3, "Go"))
category = models.IntegerField(choices=CHOICES)
pub_time = models.DateField()
publisher = models.ForeignKey(to="Publisher")
authors = models.ManyToManyField(to="Author") class Publisher(models.Model):
title = models.CharField(max_length=32) def __str__(self):
return self.title class Author(models.Model):
name = models.CharField(max_length=32) def __str__(self):
return self.name

models.py

ModelSerializer

既然上面的写法很low,DRF提供给了我们ModelSerializer,之前序列化器继承的是serializers.Serializer,现在要继承serializers.ModelSerializer

把之前的BookSerializer类里的东西删掉重写

class BookSerializer(serializers.ModelSerializer):

    class Meta:
model = Book # 对应的表名
fields = "__all__" # 显示所有的字段
# fields = ['id','title'] # 显示指定的字段
# exclude = ['id', 'title'] # 不显示指定的字段

这样我们访问这个接口查看数据

会发现Choise字段和关联表的字段不是我们想要的,我们可以加上depth来让它显示成为我们想要的值,后面的值是表示几层,因为book表和author,publisher表都是一层关联,另外两者表没有一对多和多对一的关系,所以我们可以写成depth=1

class BookSerializer(serializers.ModelSerializer):

    class Meta:
model = Book # 对应的表名
fields = "__all__" # 显示所有的字段
# fields = ['id','title'] # 显示指定的字段
# exclude = ['id', 'title'] # 不显示指定的字段
depth = 1 # 会让你这些所有的外键关系变成read_only = True

在来请求下这个接口

这样我们虽然解决了一对一和多对多的字段,但是Chiose字段还不是显示我们想要的数据,而且depth会让你这些所有的外键关系变成read_only = True,所以实际开发中都不用,都是重写

重写字段

class BookSerializer(serializers.ModelSerializer):
# 重写publisher字段
publisher_info = serializers.SerializerMethodField()
author_info = serializers.SerializerMethodField() def get_publisher_info(self, obj):
# 函数名为 get_自定义的字段名
# return了一个'ok',表示上面的publisher_info='ok',会返回给前端
return 'ok' def get_author_info(self, obj):
return 'yes' class Meta:
model = Book # 对应的表名
fields = "__all__" # 显示所有的字段
# fields = ['id','title'] # 显示指定的字段
# exclude = ['id', 'title'] # 不显示指定的字段

其中的obj就是我们在views.py里序列化的每个对象,也就是下面的book_queryset

 ser_obj = BookSerializer(book_queryset, many=True)

请求接口

会发现我们重写的数据都返回给了调用这个接口的,所以我们可以自定义需要返回哪些字段。

class BookSerializer(serializers.ModelSerializer):
# 重写publisher字段
publisher_info = serializers.SerializerMethodField()
author_info = serializers.SerializerMethodField()
category_display = serializers.SerializerMethodField() def get_publisher_info(self, obj):
# 函数名为 get_自定义的字段名
publisher_obj = obj.publisher ForeignKey,拿到的是publisher表的对象
return {"id":publisher_obj.id,'title':publisher_obj.title} def get_author_info(self, obj):
authors_queryset = obj.authors.all() ManyToMany,.all拿到的是queryset里所有的对象
return [{'id':author.id,'name':author.name} for author in authors_queryset] def get_category_display(self, obj):
return obj.get_category_display() # 调用这个方法,会返回汉字 class Meta:
model = Book # 对应的表名
fields = "__all__" # 显示所有的字段
# fields = ['id','title'] # 显示指定的字段
# exclude = ['id', 'title'] # 不显示指定的字段

publisher_info = serializers.SerializerMethodField() 叫做方法字段,需要一个方法,把方法里的返回值赋值给该字段

上面我们自定义的字段已经显示了,然而之前的字段我们可以让它不显示,在Meta加个 extra_kwargs ,里面的是个字典,key为不显示的字段名,value如果是write_only为True,就不显示了

class BookSerializer(serializers.ModelSerializer):
# 重写publisher字段
publisher_info = serializers.SerializerMethodField(read_only=True)
author_info = serializers.SerializerMethodField(read_only=True)
category_display = serializers.SerializerMethodField(read_only=True) # Choise字段,后面必须是display def get_publisher_info(self, obj):
# 函数名为 get_自定义的字段名
publisher_obj = obj.publisher
return {"id":publisher_obj.id,'title':publisher_obj.title} def get_author_info(self, obj):
authors_queryset = obj.authors.all()
return [{'id':author.id,'name':author.name} for author in authors_queryset] def get_category_display(self, obj):
return obj.get_category_display() class Meta:
model = Book # 对应的表名
fields = "__all__" # 显示所有的字段
# fields = ['id','title'] # 显示指定的字段
# exclude = ['id', 'title'] # 不显示指定的字段
extra_kwargs = {'category':{"write_only":True},'publisher':{"write_only":True},
'authors':{"write_only":True}}

这样,当我们使用post或者put方法时,就不需要再重写create方法和update方法了

在函数里重写方法字段时,里面写了read_only=True,表示序列化时使用,而在Meta类里,默认的字段category,publisher,author为write_only,所以序列化的时候,这些字段不显示,显示的是重写的那些字段。反序列化时用的是extra_kwargs里的字段

时间格式化

如果我们在创建时间的时候,使用的是DateTimeField,类似于下面这样

update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间", help_text="更新时间")

如果想返回的时候,直接格式化好,我们就可以在序列化的时候加上这句就可以了

update_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)

但是只这样修改,返回的时间是UTC的时间,我们还需要在settings.py里更改,将原来的UTC时间改为国内的时间,找到LANGUAGE_CODE和TIME_ZONE,改为中国上海的时间,如下

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

总结

ModelSerializer

  默认生成关联的模型表里的所有字段

  配置

class Meta:

      model=表名

      fields="__all__"/["字段名",]

      exclude=["字段名",]

      depth=1 外键关系找一层 会让外键关系字段变成read_only=True

      extra_kwargs={"字段名": {配置的属性}}

  SerializerMethodField()

    方法字段 会调用它自己的钩子方法,把方法的返回值给字段

    def get_字段名(self, obj):

      循环序列化的每个模型对象就是obj

      对obj进行ORM操作

      return 自定义的数据结构

DRF--ModelSerializer的更多相关文章

  1. restful(1):序列化

    restful协议中,一切皆是资源,操作只是请求方式 model_to_dict()方法: from django.forms.models import model_to_dict obj = Pu ...

  2. drf框架serializers中ModelSerializer类简化序列化和反序列化操作

    0905自我总结 drf框架serializers中ModelSerializer类 基于seriallizer类进行简化 https://www.cnblogs.com/pythonywy/p/11 ...

  3. drf框架 - 序列化组件 | ModelSerializer (查,增,删,改)

    ModelSerializer 序列化准备: 配置 settings.py # 注册rest_framework框架 INSTALLED_APPS = [ ... 'rest_framework' ] ...

  4. DRF框架中链表数据通过ModelSerializer深度查询方法汇总

    DRF框架中链表数据通过ModelSerializer深度查询方法汇总 一.准备测试和理解准备 创建类 class Test1(models.Model): id = models.IntegerFi ...

  5. 4)drf序列化组件 Serializer(偏底层)、ModelSerializer(重点)、ListModelSerializer(辅助群改)

    知识点:Serializer(偏底层).ModelSerializer(重点).ListModelSerializer(辅助群改) 一.Serializer 偏底层 一般不用 理解原理 1.序列化准备 ...

  6. Django(46)drf序列化类的使用(ModelSerializer)

    前言 我们上篇文章使用到了Serializer类,可能有小伙伴说太过复杂,那么本篇就为大家带来更加简便的序列化类ModelSerializer ModelSerializer 先来看下ModelSer ...

  7. django drf 深入ModelSerializer

    serializer用起来稍微麻烦,可以使用ModelSerializer,类似于django里的Form与ModelForm 1.定义ModelSerializer from rest_framew ...

  8. DRF序列化和反序列化(二:ModelSerializer)

    一: rest_framework 中 serializers.Serializer的不方便之处(以下简称Serializer) a:需要定义每一个字段,并且这个字段是和models字段及其类似. b ...

  9. DRF框架(三)——media资源路径设置、多表设计复习及补充、序列化组件(ModelSerializer)操作多表(序列化与反序列化)、多表序列化与反序列化整合(重点)

    media资源路径设置  (设置好后把图片放在这个文件夹中,通过链接能访问到图片) 1.先在根目录设置一个media文件夹 2.配置settings.py,加上下面的 MEDIA_URL = '/me ...

  10. 【DRF框架】序列化组件——ModelSerializer

    ModelSerializer 1.ModelSerializer类似于ModelForm 2.根据模型自动生成一组字段 3.自带实现了.update()以及.create()方法 ModelSeri ...

随机推荐

  1. 百度地图在jsp页面加载大量轨迹导致地图卡顿

    原画线方式: //存储大量点轨迹json数组:historyPathList for(var i=0;i<historyPathList.length-1;i++){ drawColorLine ...

  2. BITCTF-MISC

    MISC 以此笔记来记录本菜鸡做misc的历程 签到85 首先看题 提示base85 打开kali,使用python的base64库来解码(内有base85解码) (其实只要输python3即可 我还 ...

  3. 多项式总结(STAGE 1)

    这么难的专题居然只给了这么短时间... 然而在NC的教导之下还是有一定的收获的. 必须打广告:0,1,2,3 附带一个垃圾博客:-1 按照习惯,堆砌结论而不加证明. Section1 导数: 基本形式 ...

  4. go语言面向对象之方法

    1.实现方法 package main import "fmt" //在面向对象编程中,一个对象其实就是一个简单的值或者一个变量,在这个 //对象中包含一些函数 //这种带有接受者 ...

  5. 阿里面试实战题3----String,StringBuilder,StringBuffer区别

    String public final class String implements java.io.Serializable, Comparable<String>, CharSequ ...

  6. Git - Git基本常用命令

    Git基本常用命令 mkdir:         XX (创建一个空目录 XX指目录名) pwd:          显示当前目录的路径. git init          把当前的目录变成可以管理 ...

  7. java基础(2):注释、关键字、标识符、数据

    1. 注释.关键字与标识符 大家可以安装一个文本编辑软件notepad++,有利于java代码的查看与编写. 1.1 程序注释 通常我们需要在源代码中添加文字用来对进行代码解释说明,但这些文字并不是J ...

  8. ABP学习资源

    Abp翻译文档:https://github.com/ABPFrameWorkGroup/AbpDocument2Chinese ABP官网:https://aspnetboilerplate.com ...

  9. 如何在父级下访问v-slot的值——vuejs

    关于作用域插槽v-slot的用法可以先看看文档 https://cn.vuejs.org/v2/guide/components-slots.html#%E4%BD%9C%E7%94%A8%E5%9F ...

  10. Vue.js+vue-element搭建属于自己的后台管理模板:创建一个项目(四)

    Vue.js+vue-element搭建属于自己的后台管理模板:创建一个项目(四) 前言 本章主要讲解通过Vue CLI 脚手架构建工具创建一个项目,在学习Vue CLI之前我们需要先了解下webpa ...