DRF--ModelSerializer
前戏
在之前我们写序列化器的时候,写的很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的更多相关文章
- restful(1):序列化
restful协议中,一切皆是资源,操作只是请求方式 model_to_dict()方法: from django.forms.models import model_to_dict obj = Pu ...
- drf框架serializers中ModelSerializer类简化序列化和反序列化操作
0905自我总结 drf框架serializers中ModelSerializer类 基于seriallizer类进行简化 https://www.cnblogs.com/pythonywy/p/11 ...
- drf框架 - 序列化组件 | ModelSerializer (查,增,删,改)
ModelSerializer 序列化准备: 配置 settings.py # 注册rest_framework框架 INSTALLED_APPS = [ ... 'rest_framework' ] ...
- DRF框架中链表数据通过ModelSerializer深度查询方法汇总
DRF框架中链表数据通过ModelSerializer深度查询方法汇总 一.准备测试和理解准备 创建类 class Test1(models.Model): id = models.IntegerFi ...
- 4)drf序列化组件 Serializer(偏底层)、ModelSerializer(重点)、ListModelSerializer(辅助群改)
知识点:Serializer(偏底层).ModelSerializer(重点).ListModelSerializer(辅助群改) 一.Serializer 偏底层 一般不用 理解原理 1.序列化准备 ...
- Django(46)drf序列化类的使用(ModelSerializer)
前言 我们上篇文章使用到了Serializer类,可能有小伙伴说太过复杂,那么本篇就为大家带来更加简便的序列化类ModelSerializer ModelSerializer 先来看下ModelSer ...
- django drf 深入ModelSerializer
serializer用起来稍微麻烦,可以使用ModelSerializer,类似于django里的Form与ModelForm 1.定义ModelSerializer from rest_framew ...
- DRF序列化和反序列化(二:ModelSerializer)
一: rest_framework 中 serializers.Serializer的不方便之处(以下简称Serializer) a:需要定义每一个字段,并且这个字段是和models字段及其类似. b ...
- DRF框架(三)——media资源路径设置、多表设计复习及补充、序列化组件(ModelSerializer)操作多表(序列化与反序列化)、多表序列化与反序列化整合(重点)
media资源路径设置 (设置好后把图片放在这个文件夹中,通过链接能访问到图片) 1.先在根目录设置一个media文件夹 2.配置settings.py,加上下面的 MEDIA_URL = '/me ...
- 【DRF框架】序列化组件——ModelSerializer
ModelSerializer 1.ModelSerializer类似于ModelForm 2.根据模型自动生成一组字段 3.自带实现了.update()以及.create()方法 ModelSeri ...
随机推荐
- 微店APP协议简要分析
1.通过抓包软件charles进行抓包,点击微信收款后,抓包内容都是加密处理过 2.加载分析定位这些字段的加密函数. WDTNThorParameterProcessor HTTPBody:task ...
- 请确保二进制储存在指定的路径中,或者调试他以检查该二进制或相关的DLL文件
出现问题原因: 编译socket.dll时,用到了openssl库. 使用libeay32.lib.ssleay32.lib生成socket.dll,就会报这样的错误 解决办法: 使用libeay32 ...
- 分析Android APK-砸壳-Fdex2
砸壳的工具千千万,但是FDex2 是最有能耐的,我尝试过各种壳,都是秒砸的.特别说明一下,360的壳,oncreated 方法还是空的,但是其他大部分内容还是有的,反正是可以参考一下的. 安装环境: ...
- DialogHost 关闭对话框
<Window x:Class="DialogHost.ClosingConfirmation.CodeBehind.MainWindow" xmlns="http ...
- 请求*.html后缀无法返回json数据的问题
在springmvc中请求*.html不可以返回json数据. 修改web.xml,添加url拦截格式.
- 用PYTHON首选的GUI库WXPYTHON做程序界面
大家好,我是A8U神经网络,今天又要跟大家分享一下wxWidgets开发神经网络程序界面的一些经验,希望对开发有兴趣的朋友有所帮助.跨平台的GUI工具库以GTK +,Qt和wxWidgets闻名. G ...
- 用Python代码写的计算器
1.极限压缩版 import re, functools def cal(formula): while re.search('(?:\d+\.?\d+|\d+)[+\-*/]', formula): ...
- Linux下安装Redis以及遇到的问题
参考链接:https://www.cnblogs.com/zdd-java/p/10288734.html https://www.cnblogs.com/uncleyong/p/9882843.ht ...
- redis 事务(悲观锁和乐观锁)
MULTI 开启事务,后续的命令会被加入到同一个事务中 事务中的操作会发送给客服端,但是不会立即执行,而是将操作放到了该事务对应的一个队列中,服务端返回QUEQUD EXEC 执行EXEC后,事务中的 ...
- python frozenset
1. 一旦初始化,并不可以改变 2. 可以作为字典的键值