前戏

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

  1. class BookSerializer(serializers.Serializer):
  2. id = serializers.IntegerField(required=False) # 只序列化,不走校验
  3. title = serializers.CharField(max_length=32, validators=[my_validate])
  4. pub_time = serializers.DateField()
  5. category = serializers.CharField(source="get_category_display", read_only=True) # 只序列化用
  6. # 因为前端传的是数字,所以需要重写
  7. post_category = serializers.IntegerField(write_only=True) # 只反序列化用
  8.  
  9. publisher = PublisherSerializer(read_only=True) # 一对多的表 只序列化用
  10. authors = AuthorSerializer(many=True, read_only=True) # 多对多的表需要指定many=True 只序列化用
  11.  
  12. publisher_id = serializers.IntegerField(write_only=True) # 只反序列化用
  13. author_list = serializers.ListField(write_only=True) # 只反序列化用
  14.  
  15. def create(self, validated_data):
  16. # validated_data校验通过的数据
  17. # 通过ORM操作给book表增加数据
  18. book_obj = Book.objects.create(title=validated_data['title'],
  19. pub_time=validated_data['pub_time'],
  20. category=validated_data['post_category'],
  21. publisher_id=validated_data['publisher_id'])
  22. book_obj.authors.add(*validated_data['author_list']) # 这个参数可能是一个列表
  23. return book_obj
  24.  
  25. def update(self, instance, validated_data):
  26. # instance 更新的book_obj对象
  27. # validated_data 校验通过的数据
  28. instance.title = validated_data.get("title",instance.title)
  29. instance.pub_time = validated_data.get("pub_time",instance.pub_time)
  30. instance.category = validated_data.get("post_category",instance.category)
  31. instance.publisher_id = validated_data.get("publisher_id",instance.publisher_id)
  32. if validated_data.get("author_list"): # 可能有多个值
  33. instance.author.set(validated_data["author_list"])
  34. instance.save() # 保存
  35. return instance
  36.  
  37. def validate_title(self, value): # 对单一字段校验
  38. if "BDYJY" not in value.upper():
  39. return value
  40. raise serializers.ValidationError('标题里含有非法字符') # 抛出错误
  41.  
  42. def validate(self, attrs): # 对多个字段校验
  43. # attrs是一个字典,里面是传过来的所有字段
  44. if 'python' in attrs['title'].lower() and attrs['post_category']==1:
  45. return attrs
  46. else:
  47. raise serializers.ValidationError('传的参数有误,请重新上传')
  1. from django.db import models
  2.  
  3. # Create your models here.
  4.  
  5. __all__ = ["Book", "Publisher", "Author"]
  6.  
  7. class Book(models.Model):
  8. title = models.CharField(max_length=32)
  9. CHOICES = ((1, "python"), (2, "Liunux"), (3, "Go"))
  10. category = models.IntegerField(choices=CHOICES)
  11. pub_time = models.DateField()
  12. publisher = models.ForeignKey(to="Publisher")
  13. authors = models.ManyToManyField(to="Author")
  14.  
  15. class Publisher(models.Model):
  16. title = models.CharField(max_length=32)
  17.  
  18. def __str__(self):
  19. return self.title
  20.  
  21. class Author(models.Model):
  22. name = models.CharField(max_length=32)
  23.  
  24. def __str__(self):
  25. return self.name

models.py

ModelSerializer

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

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

  1. class BookSerializer(serializers.ModelSerializer):
  2.  
  3. class Meta:
  4. model = Book # 对应的表名
  5. fields = "__all__" # 显示所有的字段
  6. # fields = ['id','title'] # 显示指定的字段
  7. # exclude = ['id', 'title'] # 不显示指定的字段

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

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

  1. class BookSerializer(serializers.ModelSerializer):
  2.  
  3. class Meta:
  4. model = Book # 对应的表名
  5. fields = "__all__" # 显示所有的字段
  6. # fields = ['id','title'] # 显示指定的字段
  7. # exclude = ['id', 'title'] # 不显示指定的字段
  8. depth = 1 # 会让你这些所有的外键关系变成read_only = True

在来请求下这个接口

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

重写字段

  1. class BookSerializer(serializers.ModelSerializer):
  2. # 重写publisher字段
  3. publisher_info = serializers.SerializerMethodField()
  4. author_info = serializers.SerializerMethodField()
  5.  
  6. def get_publisher_info(self, obj):
  7. # 函数名为 get_自定义的字段名
  8. # return了一个'ok',表示上面的publisher_info='ok',会返回给前端
  9. return 'ok'
  10.  
  11. def get_author_info(self, obj):
  12. return 'yes'
  13.  
  14. class Meta:
  15. model = Book # 对应的表名
  16. fields = "__all__" # 显示所有的字段
  17. # fields = ['id','title'] # 显示指定的字段
  18. # exclude = ['id', 'title'] # 不显示指定的字段

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

  1. ser_obj = BookSerializer(book_queryset, many=True)

请求接口

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

  1. class BookSerializer(serializers.ModelSerializer):
  2. # 重写publisher字段
  3. publisher_info = serializers.SerializerMethodField()
  4. author_info = serializers.SerializerMethodField()
  5. category_display = serializers.SerializerMethodField()
  6.  
  7. def get_publisher_info(self, obj):
  8. # 函数名为 get_自定义的字段名
  9. publisher_obj = obj.publisher ForeignKey,拿到的是publisher表的对象
  10. return {"id":publisher_obj.id,'title':publisher_obj.title}
  11.  
  12. def get_author_info(self, obj):
  13. authors_queryset = obj.authors.all() ManyToMany,.all拿到的是queryset里所有的对象
  14. return [{'id':author.id,'name':author.name} for author in authors_queryset]
  15.  
  16. def get_category_display(self, obj):
  17. return obj.get_category_display() # 调用这个方法,会返回汉字
  18.  
  19. class Meta:
  20. model = Book # 对应的表名
  21. fields = "__all__" # 显示所有的字段
  22. # fields = ['id','title'] # 显示指定的字段
  23. # exclude = ['id', 'title'] # 不显示指定的字段

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

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

  1. class BookSerializer(serializers.ModelSerializer):
  2. # 重写publisher字段
  3. publisher_info = serializers.SerializerMethodField(read_only=True)
  4. author_info = serializers.SerializerMethodField(read_only=True)
  5. category_display = serializers.SerializerMethodField(read_only=True) # Choise字段,后面必须是display
  6.  
  7. def get_publisher_info(self, obj):
  8. # 函数名为 get_自定义的字段名
  9. publisher_obj = obj.publisher
  10. return {"id":publisher_obj.id,'title':publisher_obj.title}
  11.  
  12. def get_author_info(self, obj):
  13. authors_queryset = obj.authors.all()
  14. return [{'id':author.id,'name':author.name} for author in authors_queryset]
  15.  
  16. def get_category_display(self, obj):
  17. return obj.get_category_display()
  18.  
  19. class Meta:
  20. model = Book # 对应的表名
  21. fields = "__all__" # 显示所有的字段
  22. # fields = ['id','title'] # 显示指定的字段
  23. # exclude = ['id', 'title'] # 不显示指定的字段
  24. extra_kwargs = {'category':{"write_only":True},'publisher':{"write_only":True},
  25. 'authors':{"write_only":True}}

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

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

时间格式化

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

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

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

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

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

  1. LANGUAGE_CODE = 'zh-hans'
  2.  
  3. 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. 微店APP协议简要分析

    1.通过抓包软件charles进行抓包,点击微信收款后,抓包内容都是加密处理过  2.加载分析定位这些字段的加密函数. WDTNThorParameterProcessor HTTPBody:task ...

  2. 请确保二进制储存在指定的路径中,或者调试他以检查该二进制或相关的DLL文件

    出现问题原因: 编译socket.dll时,用到了openssl库. 使用libeay32.lib.ssleay32.lib生成socket.dll,就会报这样的错误 解决办法: 使用libeay32 ...

  3. 分析Android APK-砸壳-Fdex2

    砸壳的工具千千万,但是FDex2 是最有能耐的,我尝试过各种壳,都是秒砸的.特别说明一下,360的壳,oncreated 方法还是空的,但是其他大部分内容还是有的,反正是可以参考一下的. 安装环境: ...

  4. DialogHost 关闭对话框

    <Window x:Class="DialogHost.ClosingConfirmation.CodeBehind.MainWindow" xmlns="http ...

  5. 请求*.html后缀无法返回json数据的问题

    在springmvc中请求*.html不可以返回json数据. 修改web.xml,添加url拦截格式.

  6. 用PYTHON首选的GUI库WXPYTHON做程序界面

    大家好,我是A8U神经网络,今天又要跟大家分享一下wxWidgets开发神经网络程序界面的一些经验,希望对开发有兴趣的朋友有所帮助.跨平台的GUI工具库以GTK +,Qt和wxWidgets闻名. G ...

  7. 用Python代码写的计算器

    1.极限压缩版 import re, functools def cal(formula): while re.search('(?:\d+\.?\d+|\d+)[+\-*/]', formula): ...

  8. Linux下安装Redis以及遇到的问题

    参考链接:https://www.cnblogs.com/zdd-java/p/10288734.html https://www.cnblogs.com/uncleyong/p/9882843.ht ...

  9. redis 事务(悲观锁和乐观锁)

    MULTI 开启事务,后续的命令会被加入到同一个事务中 事务中的操作会发送给客服端,但是不会立即执行,而是将操作放到了该事务对应的一个队列中,服务端返回QUEQUD EXEC 执行EXEC后,事务中的 ...

  10. python frozenset

    1. 一旦初始化,并不可以改变 2. 可以作为字典的键值