0. 环境创建

* 1. 新建一个项目

* 2. 修改 tempaltes路径问题
# 修改模板文件路径拼接问题
'DIRS': [BASE_DIR, 'templates']
* 3. 在app01下创建表模型
from django.db import models# Create your models here.
class Book(models.Model):# 主键id = models.AutoField(primary_key=True, verbose_name='主键')# 书名title = models.CharField(max_length=32, verbose_name='书名')# 价格price = models.DecimalField(max_digits=5, decimal_places=3)# 作者author = models.CharField(max_length=32, verbose_name='作者')# 出版社publish = models.CharField(max_length=32, verbose_name='出版社')
* 4. 生成表生成操作记录 python manage.py makemigrations数据库迁移 python manage.py migrate

* 5. 在项目app01下的tests.py中添加两条数据
# Create your tests here.
import os
import sysif __name__ == "__main__":os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DRF1_serializers.settings")import djangodjango.setup()# 导入模型层from app01.models import Bookbook_list = [{'title': '穿越诸天万界','price': 12.3,'author': 'aa','publish': '飞卢小说网'},{'title': '洪荒道尊','price': 32.1,'author': 'bb','publish': '飞卢小说网'}]# 生成对象并添加到列表中queryset_list = []for dic in book_list:queryset_list.append(Book(**dic))# 批量插入Book.objects.bulk_create(queryset_list)

1. 序列化组件

序列化组件Serializer是rest_framework的.
导入序列化组件:
from rest_framework.serializers import Serializer
1. 序列化: 序列化器会把模型对象转为字典, 经过response之后变成json格式字符串, 发送给客户端.
2. 反序列化: 序列化器可以将字典转为模型对象, 客户端发送的数据, 经过request以后变成字典.
3. 反序列化完成数据校验功能.

1.1 序列化的过程

1. 写一个序列化类, 这个类需要继承Serializer
2. 在类中写需要序列化的字段, 字段 = serializers.转换的类型(), 将表字段对应的数据转为指定格式数据
3. 在视图中导入序列化类, 实例化得到一个序列化器对象, 需要转化的数据对象作为第一个参数, 传入序列化类中
4. 序列化类实例化得到一个对象, 序列列化的数据是一个字典, 被封装到对象的.data方法中
5. 字典数据使用rest_framework提供的Response函数放回
rest_framework提供的Response, 会根据不同的客户端返回不同的信息, 如浏览器访问, 返回一个页面.
使用JsonResponse返回的数据就都是json格式的字符串.

1.2 字段类型

对于DRF框架中序列化器所有的字段类型,我们可以到 rest_framework.fields 模块中进行查看
序列化器类定义字段类型和Django框架中ORM的字段类型是一样.
序列化器中常用的字段类型如下
字段 字段构造方式
BooleanField BooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)max_digits: 最多位数decimal_palces: 小数点位置
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
ChoiceField ChoiceField(choices)choices与Django的用法相同
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)

1.3 获取数据(序列化操作)

* 1. 在app01项目下新建一个res.py文件
# 导入序列化器
from rest_framework import serializers  # 导入serializers组件
# 导入序列化中的串行器
from rest_framework.serializers import Serializer  # Serializer是一个类# 定义序列化组件的类, 继承串行器
class BookSerializer(Serializer):# 定义需要序列化的字段, 没有定义的不会处理# 主键id = serializers.CharField()# 书名title = serializers.CharField()# 价格 浮点型的值也转为字符串price = serializers.CharField()# 作者author = serializers.CharField()
* 2. 定义一个路由
    # Book视图类的  定义一个有名分组url(r'^book/(?P<pk>\d+)/', views.Book.as_view())
* 3. 定义视图类 使用APIView
from django.shortcuts import render, redirect, HttpResponse# 0. 导入 APIView, 使用rest_framework模块一定要去app应用列表中注册
from rest_framework.views import APIView# 1. 定义视图类
class BookView(APIView):# 1.1 定义get方法, 接收request对象 与有名分组匹配到的的主键def get(self, request, pk):# 1.3 导入 模型层from app01.models import Book# 1.4 通过 主键获取对应的数据对象book_obj = Book.objects.filter(pk=pk).first()print(book_obj)# 1.5 导入图书序列化器from app01.res import BookSerializer# 1.6 使用序列化将模型对象序列化成字典 BookSerializer是一个类, 加括号实例化执行__init__方法book_dic = BookSerializer(book_obj)# 1.7 序列化成字典的数据被封装到对象的data方法中, 通过.data获取序列化之后的数据print(book_dic.data)# 1.8 导入rest_framework的 Response, Response继承了Django的HttpResponse, 返回的数据也是HttpResponse格式from rest_framework.response import Response# 1.9 返回字典数据return Response(book_dic.data)
将导入模块提出
from django.shortcuts import render, redirect, HttpResponse# 0. 导入 APIView, 使用rest_framework模块一定要去app应用列表中注册
from rest_framework.views import APIView# 1.3 导入 模型层
from app01.models import Book# 1.5 导入图书序列化器
from app01.res import BookSerializer# 1.8 导入rest_framework的 Response, Response继承了Django的HttpResponse, 返回的数据也是HttpResponse格式
from rest_framework.response import Response# 1. 定义视图类
class BookView(APIView):# 1.1 定义get方法, 接收request对象 与有名分组匹配到的的主键def get(self, request, pk):# 1.4 通过 主键获取对应的数据对象book_obj = Book.objects.filter(pk=pk).first()print(book_obj)# 1.6 使用序列化将模型对象序列化成字典 BookSerializer是一个类, 加括号实例化执行__init__方法book_dic = BookSerializer(book_obj)# 1.7 序列化成字典的数据被封装到对象的data方法中, 通过.data获取序列化之后的数据print(book_dic.data)# 1.9 返回字典数据return Response(book_dic.data)
* 4. 启动项目
* 5. 在Postman中测试GET 127.0.0.1:8000/api/books/v1/1/定义的字段都处理了, 作者字段没有处理

* 6. 在浏览器中访问: 127.0.0.1:8000/api/books/v1/1/
使用srest_framework的Response返回数据的时候, 针对浏览器, 会渲染一个页面返回,
这个页面使用通过srest_framework模块的app去生成的, 需要对这个app进行注册.
出现这个错误之后, 去app列表中注册rest_framework即可.

* 7. 应用列表中注册 rest_framework app
INSTALLED_APPS = [...'rest_framework',
]
* 8. 重新访问

1.4 反序列化的过程

1. 写一个序列化类, 这个类需要继承Serializer
2. 在类中写需要反序列化的字段, 字段 = serializers.转换的类型(限制条件)2.1 将请求的数据转为指定类型数据, json格式字符串(字典) --> Python字典2.2 转换数据的时候做数据的校验, 默认的参数达不到要求, 可以自定义钩子函数
参数名称 作用
max_length 字符串最大长度
min_length 字符串最小长度
max_value 数字最大值
min_value 数字最小值
allow_blank 是否允许为空
trim_whitespace 是否截切空白字符
3. 在视图中导入序列化类, 实例化得到一个序列化器对象, 需要转化的数据对象作为第一个参数, 修改的数据作为第二个参数, 传入序列化类中.对象 = xxserializer(数据对象, request.data)推荐 对象 xxserializer(instance=数据对象, data=request.data)
4. 数据校验对象.is_valid, 判断数据是否合法is_valid(raise_exception=True):  数据校验不通过直接return返回错误提示对象.errors 校验不通过的异常信息对象.error_messages 异常的提示信息
5. 检验成功就保存数据对象.sava(), 需要在序列化类重新updata方法.
6. 检验不成功, 写错误的逻辑

1.5 修改数据(反序列化+数据校验)

修改的数据的请求put 与 patch 虽然被区分为局部修改和全局修改, 倒是在使用时, 没人严格区分, 使用那个都行.
1. 修改app01下的res.py 中的序列化类, 添加校验条件
# 定义序列化组件的类, 继承串行器
class BookSerializer(Serializer):# 定义需要序列化的字段, 这些字段是必须要传递的# 主键   括号校验 在反序列化 字典转模型的时候会触发id = serializers.CharField()# 书名title = serializers.CharField(min_length=3, max_length=5)# 价格 浮点型的值也转为字符串price = serializers.CharField()# 作者author = serializers.CharField()
* 2. 写视图类的put方法
    # 定义put方法 接收request对象, 与有名分组匹配到的的主键def put(self, request, pk):"""对数据修改需要对数据做检验"""# 1. 通过组件获取对应的数据对象book_obj = Book.objects.filter(pk=pk).first()# 2. 反序列化 字段-->模型, 序列化类(数数据对象, 修改的数据)book_dic = BookSerializer(instance=book_obj, data=request.data)# 3. 判断数据校验结果if book_dic.is_valid():# 数据校验合格之后将数据存储book_dic.save()  # NotImplementedError:必须实现`update()`。back_dic = {'code': 200,'msg': '修改成功!',# 将修改后的数据返回 单个数据返回的是对象'book_obj': book_dic.data}else:back_dic = {'code': 404,'msg': f'修改失败: {book_dic.errors}'}return Response(back_dic)

序列化器的对象, 自己是没有save方法的, 父类中定义了该方法. 它判断当前需要更新数据就会调用update方法
update方法利用Python面向对象的多态特性, 在父类中限制子类必须有某个方法, 实现某个功能.
* 3. 在序列化类定义update方法.每个表的数据都是不一样的, 写这个模板的作者刚脆不提供数据更新到数据库的方法, 在父类中限制该方法必须实现, 让使用者自己写update, 将数据更新到数据库
# 定义序列化组件的类, 继承串行器
class BookSerializer(Serializer):# 定义需要序列化的字段# 主键   括号校验 在反序列化 字典转模型的时候会触发id = serializers.CharField()# 书名title = serializers.CharField(min_length=3, max_length=5)# 价格 浮点型的值也转为字符串price = serializers.CharField()# 作者author = serializers.CharField()# 定义update方法  book的数据对象  检验后的数据-->字典def update(self, instance, validated_data):# 将book_obj对象的数据 数据逐个修改for key in validated_data:# 放射   对象      属性    值setattr(instance, key, validated_data.get(key))# 保存数据, 写入数据库  Django ORM的save()instance.save()# 修改之后将数据返回return instance
* 5. 在Postman中测试: (* 序列化器类中定义的字段必须传数据, 不然, 反序列化该字段就会报错, 不能为空)请求方式: put请求地址: 127.0.0.1:8000/api/books/v1/1/请求格式: raw-JSON请求数据:
{    "id": "1","title": "穿越诸天","price": "12.30","author": "aaa",
}

* 6. 检验测试tilte字段的修改限制条件: 字符串 最长5位, 最少3为请求数据:
{"title": "穿越","price": "12.30","author": "aaa",
}

# 3. 判断数据校验结果, 如有数据不合格就直接return返回
book_dic.is_valid(raise_exception=True)
# 后面的代码全部注释

1.6 局部钩子检验

校验的顺序, 是一个一个字段验证的, 先验证参数规则, 马上检查自己对应的局部钩子.
在局部钩子中使用 raise ValidationError('xx'), 抛出的异常被捕获, 并封装到对象.errors中.
# 导入抛异常模板
from rest_framework.exceptions import ValidationError
检验书的价格不能超过300.00
* 1. 在序列化类中写局部钩子函数, 局部钩子的函数名 validdate_需要校验的字段名称必须接收一个date参数, 这个参数就是, 该字段提交的值, 在经过第一层serializers.xx(x)校验之后的数据.
# 导入序列化器
from rest_framework import serializers  # 导入serializers组件
# 导入序列化中的串行器
from rest_framework.serializers import Serializer  # Serializer是一个类# 导入抛异常模板
from rest_framework.exceptions import ValidationError# 定义序列化组件的类, 继承串行器
class BookSerializer(Serializer):# 定义需要序列化的字段# 主键   括号校验 在反序列化 字典转模型的时候会触发id = serializers.CharField()# 书名title = serializers.CharField(min_length=3, max_length=5)# 价格 浮点型的值也转为字符串price = serializers.CharField()# 作者author = serializers.CharField()# 定义update方法  book的数据对象  检验后的数据-->字典def update(self, instance, validated_data):# 将数据逐个修改for key in validated_data:# 放射   对象      属性    值setattr(instance, key, validated_data.get(key))# 保存, Django ORM的save()instance.save()# 修改之后将数据返回return instance# 定义一个局部钩子, 判断修改的价格不能超过300.00def validate_price(self, data):print(data, type(data))# 满足条件就将值返回if float(data) < 300.00:return data# 抛出异常, 使用rest_framework的  ValidationError 验证错误封装异常提示信息else:return ValidationError('价格过高')
* 2. 在Postman中测试: 请求方式: put请求地址: 127.0.0.1:8000/api/books/v1/1/请求格式: raw-JSON请求数据:
{   "id": "1","title": "穿越诸天","price": "301.00","author": "aaa"
}

1.7 全局钩子

校验的顺序, 等所有的字段检验了参数规则和局部钩子之后, 得到了所有校验合格的数据, 才执行全局钩子.
字段多了, 少了, 没有经过检验的都会被排除.
检验书名不能与作者社重名
* 2. 在序列化类中写全局钩子函数, 全局钩子的函数名 validdate必须接收一个validdate_tate参数, 这个参数就是, 经过第一层serializers.xx(x)校验后所有合格的数据.
    # 定义全局钩子def validate(self, validate_data):print(validate_data, type(validate_data))  # 有序字典# 取值title = validate_data.get('title')author = validate_data.get('author')# 满足条件就将值返回if author != title:return validate_data# 抛出异常, 使用rest_framework的  ValidationError 验证错误封装异常提示信息else:raise ValidationError('书名与作者名重名!')
* 2. 在Postman中测试: 请求方式: put请求地址: 127.0.0.1:8000/api/books/v1/1/请求格式: raw-JSON请求数据:
{   "id": "1","title": "穿越诸天","price": "30.00","author": "穿越诸天"
}
 第一层数据检验之后合格之后被封装成一个有序字典存, 在定义全局钩子的时候, 会被作为一个参数进行传递.OrderedDict([('id', '1'), ('title', '穿越诸天'),('price', '30.00'),('author', 'aaa')]) <class 'collections.OrderedDict'>

1.8 valifaters参数检验

使用使用字段的validators指定一个校验函数, xxx.CharField(validators=[函数名1, 函数名2])
可以通过函数的形式去检验数据, 使用和局部钩子一样, 写成函数形式, 不多见.
定义多个序列化器类的时候, 校验多个表中的字段时使用.
可以指定多个检验的函数.
# 导入序列化器
from rest_framework import serializers  # 导入serializers组件
# 导入序列化中的串行器
from rest_framework.serializers import Serializer  # Serializer是一个类# 导入抛异常模板
from rest_framework.exceptions import ValidationErrordef check_keyword(data):# 不能以xx开头if data.startswith('xx'):raise ValidationError('作者名称不能以xx开头!')else:return data
# 定义序列化组件的类, 继承串行器
class BookSerializer(Serializer):# 定义需要序列化的字段# 主键   括号校验 在反序列化 字典转模型的时候会触发id = serializers.CharField()# 书名title = serializers.CharField(min_length=3, max_length=5)# 价格 浮点型的值也转为字符串price = serializers.CharField()# 作者author = serializers.CharField(validators=[check_keyword])# 定义update方法  book的数据对象  检验后的数据-->字典def update(self, instance, validated_data):# 将数据逐个修改for key in validated_data:# 放射   对象      属性    值setattr(instance, key, validated_data.get(key))# 保存, Django ORM的save()instance.save()# 修改之后将数据返回return instance

1.8 通用参数

参数名称 说明
read_only 表明该字段仅用于序列化数据, 默认为False
write_only 表明该字段仅用于反序列化数据, 默认为False
required 表明该字段在反序列化时必须输入, 默认为True,
default 反序列化时使用设置的默认值
allow_null 表明该字段是否允许传入None, 默认为False
validators 该字段可以指定使用的验证器, [func]
error_messages 包含错误编号与错误信息的字典
在序列化字段的时候, 读写都是同一个序列化类, 这样就会出现某个字段在读的时候需要, 某写字段在写的时候需要.
read_only=True   在查询到数据序列化成字典的时候, 该字段会展示, 在传数据的时候不需要写该字段的值.
write_only=True  在写入数据反序列化的成模型对象的时候, 该字段需要传值, 在查询该数据的时候不会展示.
class BookSerializer(Serializer):# 定义需要序列化的字段# 主键   括号校验 在反序列化 字典转模型的时候会触发id = serializers.CharField(read_only=True)  # 只查不传...

class BookSerializer(Serializer):# 定义需要序列化的字段# 主键   括号校验 在反序列化 字典转模型的时候会触发id = serializers.CharField(write_only=True)  # 只传不查...

1.9 查询所有数据

查询所有可以新建一个路由, 也可以在原来的get请求上, 对pk的值进行判断,
有值则是单条数据查询, 没值则是查询全部.
多个数据序列化的时候序列化类(需要设置many=True)
    # 查询所有表数据url(r'^api/books/v1/$', views.BooksView.as_view()),
class BooksView(APIView):def get(self, request):# 获取所有数据all_books_obj = Book.objects.all()# 序列化成字段all_books = BookSerializer(instance=all_books_obj, many=True)back_dic = {'code': 200,'msg': '查询成功!','book_obj': all_books.data}return Response(back_dic)

1.10 添加数据

    # 查询所有表数据/新增表数据url(r'^api/books/v1/$', views.BooksView.as_view()),
添加数据是没有数据对象的值, 只需要将request.data的值创建即可, 需要使用关键的形式传递.
序列化类的第一个位置形参是instance, 如果以位置参数进行传递就出错了.
    # post请求新增数据def post(self, request):# 将request.data 的数据传递给序列化类, 以关键字的形式传book_obj = BookSerializer(data=request.data)# 检验数据if book_obj.is_valid():# 校验成功, 将数据保存book_obj.save()back_dic = {'code': 201,'msg': '创建成功!','book_obj': book_obj.data}# 数据校验不成功else:back_dic = {'code': 101,'msg': f'数据检验不通过{book_obj.errors}'}return Response(back_dic)

序列化器的对象, 自己是没有save方法的, 父类中定义了该方法, 它判断当前需要创建数据就会调用create方法
create方法利用Python面向对象的多态特性, 在父类中限制子类必须有某个方法, 实现某个功能.
在序列化类定义create方法.
每个表的数据都是不一样的, 写这个模板的作者刚脆不提供创建数据到数据库的方法,
在父类中限制该方法必须实现, 让使用者自己写create, 创建数据到数据库.
# 导入模型层的表
from app01.models import Book# 接收校验之后的数据
def create(self, validated_data):# 创建数据到数据库instance = Book.objects.create(**validated_data)# 将数据返回, 封装序列化对象.data方法需要这个参数, 不然.data就没有值了, 不返回会抛出异常# AssertionError: `create()` did not return an object instance.return instance
* 2. 在Postman中测试: 请求方式: put请求地址: 127.0.0.1:8000/api/books/v1/请求格式: raw-JSON请求数据: (id设置为只读模式, 在写入数据的时候, 该字段不要参数)
{   "title": "这本书很酷","price": "18.00","author": "NN","publish": "起点大说网"
}

1.11 删除

删除在有名分组获取主键的的视图类中写,
删除数据之间过滤数据删除即可, 不需要使用序列化器, 不需要返回什么数据, 返回响应信息即可.
    # Book视图类的路由, 路由中有api字眼, 路由即资源 名称使用名字 推荐是复数 携带版本号 定义一个有名分组url(r'^api/books/v1/(?P<pk>\d+)/', views.BookView.as_view()),
# 接收request对象 与有名分组匹配到的主键值
def delete(self, request, pk):# 过滤删除, 删除数据会返回一个影响的行数num = Book.objects.filter(pk=pk).delete()print(num)  # (1, {'app01.Book': 1})# 返回响应状态码if num[0]:back_dic = {'code': 100,'msg': '删除成功'}else:back_dic = {'code': 101,'msg': '需要删除的数据不存在!'}return Response(back_dic)

再次删除

1.12 封装响应状态信息

每个接口都需要返回响应信息, 可以加响应信息利用类来实现.
* 1. 在app001下创建一个request_msg.py
* 2. 写一个MyResponse类
class MyResponse():def __init__(self):self.code = 200self.msg = '成功'@propertydef get_dict(self):return self.__dict__
* 3. 在接口中调用MyResponse生成响应信息如果有数据对象需要返回, 对象.book_obj = 序列化对象.data 即可
# 接收request对象 与有名分组匹配到的主键值
def delete(self, request, pk):# 过滤删除, 删除数据会返回一个影响的行数num = Book.objects.filter(pk=pk).delete()print(num)# 返回响应状态码if num[0]:# 生成对象res = MyResponse()# 获取所有数型的数据 是一个字段格式数据back_dic = res.get_dictelse:# 生成对象res = MyResponse()# 修改数据值res.code = 101res.msg = '需要删除的数据不存在!'# 获取所有数型的数据 是一个字段格式数据back_dic = res.get_dictreturn Response(back_dic)

2. 模型序列化组件

模型序列化组件可以省去定义字段的转换的过程. 模型序列化器需要继承ModelSerializer类.
它的使用方法与序列化器是一样的.
* 模型序列化组件对应上了模型表, create与update方法就不需要自己写了.
# 导入模型序列化类
from rest_framework.serializers import ModelSerializer
模型类中必须定义Meta类, 在Meta类中必须定义field属性或exclude属性, 两者只能出现一个.
field = '__all__' 所有字段都转换
field = ['字段1', '字段2', ...] 指定转换的字段
exclude = ['字段1', '字段2', ...]  排除指定字段
extra_kwargs = {'字段1': {'read_only': True}} 为字段添加条件, 设置id字段默认开启了只读!
局部钩子和全局钩子直接后面添加即可, 使用方法与序列化器时一模一样的.class Meta:model = xxx# 定义局部钩子...# 定义全局钩子...
* 1. 定义一个模型序列化类
# 导入模型序列化类
from rest_framework.serializers import ModelSerializer# 定义一个模型类序列化器
class BookModelsSerializer(ModelSerializer):# 定义元类# 必有有 Meta类 AssertionError: Class BookModelsSerializer missing "Meta" attributeclass Meta:# 指定序列化的模型表, models.py 的变model = Book# 必须有modes属性 AssertionError: Class BookModelsSerializer missing "Meta.model" attribute# 指定需要转换的字段  '__all__' 表示所有字段fields = '__all__'
* 2. 新建一个路由, 查询所有的数据
    # 模型序列化器, 查询所有数据url(r'api/books2/v1/', views.Book2View.as_view())
* 3. 定义视图类中, 在请求的方法中使用模型序列化器.
class Book2View(APIView):# 查询所有数据, 没有主键def get(self, request):# 查询表中所有的数据all_book_obj = Book.objects.all()# 导入模型序列类, 使用模型序列化器, 将数据作为参数进行传递from app01.res import BookModelsSerializerbook_dic = BookModelsSerializer(instance=all_book_obj)print(book_dic)# 返回响应信息res = MyResponse()# 添加属性back_dic = res.get_dict# 所有的属性通过__dict__转为字段back_dic.book_obj = book_dic.data# 返回return Response(back_dic)
* 5. 在Postman中测试: 请求方式: get请求地址: 127.0.0.1:8000/api/books2/v1/

* 6. 指定字段转换
# 定义一个模型类序列化器
class BookModelsSerializer(ModelSerializer):# 定义元类class Meta:# 指定序列化的模型表, models.py 的变model = Book# 指定需要转换的字段  fields = ['id', 'title']

* 7. 排除字段
# 定义一个模型类序列化器
class BookModelsSerializer(ModelSerializer):# 定义元类class Meta:# 指定序列化的模型表, models.py 的变model = Book# 排除不需要转换的字段  exclude = ['id', 'title']

* 8. 给字段添加限制条件老版本是可以 write_only_fields = ['字段1', '字段2'] 现在已经被禁用了, 设置了不生效
id字段默认是开启了只读, 就是在传给数据的时候id字段不需要传递参数.
AssertionError: 不能同时设置 `read_only` 和 `write_only`
# 定义一个模型类序列化器
class BookModelsSerializer(ModelSerializer):# 定义元类class Meta:# 指定序列化的模型表, models.py 的变model = Book# 指定需要转换的字段  '__all__' 表示所有字段fields = '__all__'# 添加限制条件, 只写, 不读extra_kwargs = {'title': {'write_only': True},'price': {'write_only': True}}

* 9. 混合使用
# 定义一个模型类序列化器
class BookModelsSerializer(ModelSerializer):# 在这里定义的字段会将下面的覆盖后面的设置title = serializers.CharField(write_only=True)# 定义元类class Meta:# 指定序列化的模型表, models.py 的变model = Bookfields = '__all__'extra_kwargs = {'title': {'write_only': False}}  # 关闭失败

3. many关键字参数分析

序列化组件的many关键字参数分析
* 1. 修改视图类, 分类查单条数据和所有数据
class Book2View(APIView):# 查询所有数据, 没有主键def get(self, request):# 查询表中所有的数据all_book_obj = Book.objects.all()# 导入模型序列类, 使用模型序列化器, 将数据作为参数进行传递from app01.res import BookModelsSerializerall_dic = BookModelsSerializer(instance=all_book_obj, many=True)# 查询单条数据only_obj = Book.objects.first()only_dic = BookModelsSerializer(instance=only_obj)print(type(all_dic), type(only_dic))# <class 'rest_framework.serializers.ListSerializer'> <class 'app01.res.BookModelsSerializer'># 返回响应信息res = MyResponse()res.book_obj = all_dic.databack_dic = res.get_dictreturn Response(back_dic)
mant=True  <class 'rest_framework.serializers.ListSerializer'>
mant=False <class 'app01.res.BookModelsSerializer'>
类名加()
1. 先调用__net__方法, 生成空对象,
2. 在调用__init__方法, 实例化为空对象添加属性
* 类的__net__方法控制了对象的生成
追溯__net__,
BaseSerializer有__new__
Serializer(BaseSerializer)
ModelsSerializer(Serializer)
BookModelsSerializer(ModelsSerializer)

    # cls 是当前所在位置的类def __new__(cls, *args, **kwargs):# We override this method in order to automagically create# `ListSerializer` classes instead when `many=True` is set.# 从关键字总取many的值if kwargs.pop('many', False):# 如果many为True 则走当前类的绑定方法many_initreturn cls.many_init(*args, **kwargs)# 没有传many为True的, 正常序列化得到 app01.res.BookModelsSerializer return super().__new__(cls, *args, **kwargs)

4. Serializer高级用法

4.1 创建环境

* 1. 创建app02
 python manage.py startapp app02
* 2. 注册app02
    INSTALLED_APPS = [...'app02.apps.App02Config']
* 3. 路由分发
# 项目名文件夹下urls.py 总路由
from django.conf.urls import url
from django.contrib import admin
# 导入视图层
from app01 import views# 导入include
from django.conf.urls import include
from app02 import urls
urlpatterns = [...# app02的路由url(r'^api/app2/(?P<pk>\d+)/', include(urls))
]
* 4. app02项目下创建urls.py
from django.shortcuts import render# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Responseclass App2Book(APIView):# get方法def get(self, request, pk):return Response({'code': 200})
* 5 . 创建表模型
from django.db import models# Create your models here.# 0. 书籍表
class Book(models.Model):# 0.1 id 自动创建# 0.2 书名title = models.CharField(max_length=32, verbose_name='书名')# 0.3 价格price = models.CharField(max_length=32, verbose_name='价格')# 0.4 出版时间pub_date = models.DateField()# 0.5 外键字段 on_delete 级联删除publish = models.ForeignKey('Publish', on_delete=models.CASCADE,null=True, verbose_name='关联出版社表')# 0.6 外键字段author = models.ManyToManyField('Author', verbose_name='关联作者表')def __str__(self):return self.title# 1.定义出版社
class Publish(models.Model):# 1.0 id字段自动增加# 1.1 出版社名字name = models.CharField(max_length=32, verbose_name='出版社名字')# 1.2 邮箱email = models.EmailField(verbose_name='出版社邮箱')def __str__(self):return self.name# 2. 作者表
class Author(models.Model):# 2.1 id自动增加# 2.2 作者名字name = models.CharField(max_length=32, verbose_name='作者名字')# 2.3 作者邮箱email = models.EmailField(verbose_name='作者邮箱')
* 6. 生成表生成表记录 python3.6 manage.py makemigrations app02数据库迁移 python3.6 manage.py migrate app02
* 7. 在app02的texts.py中为表条件数据
from django.test import TestCase# Create your tests here.
import os
import sysif __name__ == "__main__":os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DRF1_serializers.settings")import djangodjango.setup()# 0. 导入模型层from app02 import models# 1. 出版社表数据models.Publish.objects.create(name='起点小说网', email='110@qq.com')models.Publish.objects.create(name='飞卢小说网', email='120@qq.com')# 2. 作者表数据models.Author.objects.create(name='kid', email='130@qq.com')models.Author.objects.create(name='qq', email='140@qq.com')# 3. 书籍表数据import datetimedate = datetime.date(2021, 4, 2)models.Book.objects.create(title='开局签到荒古圣体', price=123, pub_date=date, publish_id=1)models.Book.objects.create(title='开局签到荒古圣体', price=123, pub_date=date, publish_id=2)# 书籍表与作者的第三张表book1_obj = models.Book.objects.filter(pk=1).first()# 第一本书绑定两个作者book1_obj.author.add(1, 2)book2_obj = models.Book.objects.filter(pk=2).first()# 第二本书绑定一个作者book1_obj.author.add(1)

* 8. 创建序列化器
# 0. 导入序列化组件模板
from rest_framework import serializers
# 1. 导入序列化类
from rest_framework.serializers import Serializer# 2. 定义序列化器
class BookSerializer(Serializer):# 写需要转换的字段id = serializers.CharField()title = serializers.CharField()price = serializers.CharField()pub_date = serializers.CharField()# 外键字段, 触发了出版社的__str__方法publish = serializers.CharField()
* 9. 使用序列化器
from django.shortcuts import render# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Response# 导入自定义的序列化类
from app02.res import BookSerializer
# 导入模型层
from app02 import models
# 导入响应信息
from app01.request_msg import MyResponseclass App2Book(APIView):# get方法 查询pk对应的书籍数据def get(self, request, pk):# 通过主键查询数据book_obj = models.Book.objects.filter(pk=pk).first()print(book_obj)# 序列化模型数据book_dic = BookSerializer(instance=book_obj)# 返回信息res = MyResponse()res.book_obj = book_dic.databack_dic = res.get_dictprint(back_dic)return Response(back_dic)
* 10. 在Postman中测试: 请求方式: get请求地址: 127.0.0.1:8000/api/app2/books/v1/1/

转换Publish外键字段触发了Publisk的__str__方法

4.2 source字段

source字段作用:
1. 起别名: 返回的数据key值与数据库的不一致.
2. 跨表查询: 通过外键字段查询关联表的数据
3. 使用模型表的方法: 使用表模型的方法, 会自动加括号执行
自己返回的字段名不能和数据的字段名一样, 这样很容易被被人攻击获取到数据.
需要一种方式来处理, 在字段类型后面的括号中设置source属性,
eg: 别名 = serializer.CharField(source='数据库存在的字段名')
# 修改序列化类中的id字段名
uid = serializers.CharField(source='id')

跨表查询, eg: pbulsh = serializers.CharField(source='外键字段.关联表的字段')
# 查询关联表的邮箱信息
publish = serializers.CharField(source='publish.email')

在模型层的Book表中定义一个方法
# 0. 书籍表
class Book(models.Model):...# 定义一个方法def get_title(self):return f'<<{self.title}>>'
# 自动加括号调用
title = serializers.CharField(source='get_title')

4.3 SerializerMethodField

SerializerMethodField的使用配套一个方法, 在该方法定义返回的数据.
eg: 别名 = serializers.SerializerMethodField(source='外键字段/虚拟字段')
绑定方法名字: get_字段名(self, instance接收数据对象), 字段名可以是别名.
返回的数据: return 该字段展示的信息.
# 0. 导入序列化组件模板
from rest_framework import serializers
# 1. 导入序列化类
from rest_framework.serializers import Serializer# 2. 定义序列化器
class BookSerializer(Serializer):# 写需要转换的字段uid = serializers.CharField(source='id')title = serializers.CharField()price = serializers.CharField()pub_date = serializers.CharField()# 自定义放回数据 SerializerMethodField 绑定get_字段方法author_msg = serializers.SerializerMethodField(source='author')# get_字段名, 接收instance, 当前表的对象, instance是在是序列化器时传入的.def get_author_msg(self, instance):# instance == 数据对象# 查询书籍所有的作者对象all_author_obj = instance.author.all()# 封装成一个列表套字段的格式l1 = []for author_obj in all_author_obj:l1.append({'作者名字': author_obj.name, '作者邮箱:': author_obj.email})# 返回什么, 获取的数据就是什么return l1

4.4 模型序列化中使用

修改app01中res.py的模型序列化类.
单独对字段经常操作, 在上面定义字段之后, 将Meta中的字段覆盖.
# 定义一个模型类序列化器
class BookModelsSerializer(ModelSerializer):# 定义元类# 覆盖下面的设置 title字段的设置title1 = serializers.CharField(source='author')class Meta:# 指定序列化的模型表, models.py 的变model = Bookfields = '__all__'

5. 练习

* 1.新建项目编写查增改删四个接口.
* 2. 表模型 & 创建表
# 书籍表
class Book(models.Model):# 1. idid = models.AutoField(primary_key=True, verbose_name='主键')# 2. 书名title = models.CharField(max_length=32, verbose_name='书名')# 3. 作者author = models.CharField(max_length=32, verbose_name='作者')
 python3.6 manage.py makemigrationspython3.6 manage.py migrate

5.1 路由层

删, 改, 查单个数据都需要一个携带一个主键, 查全部,增不需要.
增,查全部使用一个路由, 删改查单条数据使用一个路由.
from django.conf.urls import url
from django.contrib import adminfrom app01 import viewsurlpatterns = [url(r'^admin/', admin.site.urls),# 增,查全部url(r'^api/books/v1/$', views.BookAPI1.as_view()),# 删改查单条数据url(r'^api/books/v1/(?P<pk>\d+)/', views.BookAPI2.as_view()),
]

5.2定义响应信息类

在app01下创建一个 response_msg.py文件
# 定义响应信息
class BackMsg(object):def __init__(self, code, msg, data):self.code = codeself.msg = msgself.data = data@propertydef get_data(self):return self.__dict__

5.3 视图层

from django.shortcuts import render# Create your views here.# 导入 rest_framework
from rest_framework.views import APIView
# 导入 响应函数
from rest_framework.response import Response
# 导入 响应信息
from app01.response_msg import BackMsg# 增, 查全部
class BookAPI1(APIView):# 查全部def get(self, request):back_msg = BackMsg(200, '查询成功', None)return Response(back_msg.get_data)# 增def post(self, request):back_msg = BackMsg(200, '增加成功', None)return Response(back_msg.get_data)# 改, 查, 查单个
class BookAPI2(APIView):# 查单个def get(self, request, pk):back_msg = BackMsg(200, '查询成功', None)return Response(back_msg.get_data)# 改def put(self, request, pk):back_msg = BackMsg(200, '修改成功', None)return Response(back_msg.get_data)# 删def delete(self, request, pk):back_msg = BackMsg(200, '删除成功', None)return Response(back_msg.get_data)
127.0.0.1:8000/api/books/v1/

5.4 定义序列化器

在app01下创建一个 my_serialize.py文件
# 导入序列化器组件
from rest_framework import serializers# 定义序列化器
class BookSerializer(serializers.Serializer):# 定义转换的字段book_id = serializers.IntegerField(source='id')# 书名book_title = serializers.CharField(source='title')# 作者author_name = serializers.CharField(source='author')

5.5 增加数据

获取用户提交的数据, 将用户提交的数据反序列化检验数据.
0. 数据不能为空, 默认的
1. 局部钩子函数检验 已经存在的书籍不能添加.
1. 全局钩子函数检验 书名不能与作者名一样.
局部钩子的名字以别名为主,
全局函数的接收检验合格是数据是一个有序字段, 字段的键还是表的字段. OrderedDict([('字段名1', '值'), ('字段名2', '字段')])
在写creat方法与update方法, 检验合格是数据一个普通的字典{'字段名1': '值', '字段名2': '值'}
最后返回数据的时候序列化器对象的.data数据就是一个普通的字典.{'字段名1': '值', '字段名2': '值'}
如果是创建值, 或修改值, 是需要返回数据对象的, 这个值被列化器对象的.data接收,
在没有写这两个方法且没有返回数据对象会报错, .save之前不能使用.data使用序列化器时:
序列化类(data=request.data) 会触发校验. 必须执行is_vaild()方法,
在使用.save()会触发父类规范子类的行为, 序列化类中必须实现create方法.序列化类(instance=obj, data=request.data) 会触发校验. 必须执行is_vaild()方法,
在使用.save()会触发父类规范子类的行为, 序列化类中必须实现update方法.
* 1. 视图函数
# 增, 查全部
class BookAPI1(APIView):...# 增def post(self, request):# 使用序列化器校验数据post_dic = BookSerializer(data=request.data)# 判断提交数据是否合法if post_dic.is_valid():# 保存用户的数据到数据库, 需要自己在序列化器中定义create方法.post_dic.save()# 返回正常的响应数据back_msg = BackMsg(200, '增加成功', post_dic.data)else:# 返回错误的响应数据error_msg = post_dic.errorsback_msg = BackMsg(100, error_msg, None)return Response(back_msg.get_data)
# 导入序列化器组件
from rest_framework import serializers
# 导入异常信息模块
from rest_framework.exceptions import ValidationError
# 导入模型层
from app01 import models# 定义序列化器
class BookSerializer(serializers.Serializer):# 定义转换的字段book_id = serializers.IntegerField(source='id', read_only=True)# 书名book_title = serializers.CharField(source='title')# 作者author_name = serializers.CharField(source='author')# 局部钩子, 校验书名是否存在(validate_别名为主)def validate_book_title(self, data):book_obj = models.Book.objects.filter(title=data).first()# 书名存在if book_obj:raise ValidationError('图书已经存在!')return data# 全局钩子, 校验书名是否与作者名一样def validate(self, validate_data):print(validate_data)  # OrderedDict([('title', '小说2'), ('author', '作者2')])# 取出值做检验, 值还是字段中的值, 不是别名title = validate_data.get('title')author = validate_data.get('author')if title != author:return validate_data# 抛出异常, 使用rest_framework的  ValidationError 验证错误封装异常提示信息else:raise ValidationError('书名与作者名同名')# 定义create方法, 将创建成功数据的数据返回def create(self, instance):print(instance)  # {'title': '小说2', 'author': '作者2'}book_obj = models.Book.objects.create(**instance)return book_obj
在Postman中测试:
请求方式: POST
请求地址: 127.0.0.1:8000/api/books/v1/
数据格式: raw-JSON
提交数据:
{"book_title": "小说2","author_name": "作者2"
}

重复提交

5.6 查询数据

查所有
# 导入 模型层
from app01.models import Book# 增, 查全部
class BookAPI1(APIView):# 查全部def get(self, request):# 查询所有的数据all_obj = Book.objects.all()# 判断是否有值if all_obj:# 使用序列化器get_dic = BookSerializer(instance=all_obj, many=True)back_msg = BackMsg(200, '查询成功', get_dic.data)else:back_msg = BackMsg(200, '查询成功', '没有值')return Response(back_msg.get_data)
在Postman中测试:
请求方式: GET
请求地址: 127.0.0.1:8000/api/books/v1/

单独查
# 改, 查, 查单个
class BookAPI2(APIView):# 查单个def get(self, request, pk):# 通过pk查询对应的数据值book_obj = Book.objects.filter(pk=pk).first()# 判断是否为空if book_obj:# 使用序列化book_dic = BookSerializer(instance=book_obj)back_msg = BackMsg(200, '查询成功', book_dic.data)else:back_msg = BackMsg(101, '数据不存在', None)return Response(back_msg.get_data)
在Postman中测试:
请求方式: GET
请求地址: 127.0.0.1:8000/api/books/v1/1/

查询不存在的书籍

5.7 修改数据

    # 改def put(self, request, pk):# 通过主键获取数据对象book_obj = Book.objects.filter(pk=pk).first()# 判断是否为空if book_obj:# 使用序列化器book_dic = BookSerializer(instance=book_obj, data=request.data)# 判断检验是否合格if book_dic.is_valid():book_dic.save()back_msg = BackMsg(200, '修改成功', book_dic.data)# 数据不合法else:back_msg = BackMsg(100, book_dic.errors, None)else:back_msg = BackMsg(100, '修改的数据不存在!', None)return Response(back_msg.get_data)
def update(self, instance, validated_data):# 修改对象的值, data校验之后的值print(instance, validated_data)# 修改属性for key, value in validated_data.items():setattr(instance, key, value)# 保存instance.save()return instance
在Postman中测试:
请求方式: put
请求地址: 127.0.0.1:8000/api/books/v1/5/
数据格式: raw-JSON
提交数据:
{"book_title": "开局签到荒古圣体","author_name": "kid"
}

请求地址: 127.0.0.1:8000/api/books/v1/100/

5.8 删除数据

# 删
def delete(self, request, pk):# 直接删除数据del_num = Book.objects.filter(pk=pk).delete()# 判断是都删除了值if del_num[0]:back_msg = BackMsg(200, '删除成功', None)else:back_msg = BackMsg(100, '删除的值不存在!', None)return Response(back_msg.get_data)
在Postman中测试:
请求方式: delete
请求地址: 127.0.0.1:8000/api/books/v1/1/

删除不存在的值

1. DRF 序列化组件相关推荐

  1. drf -------序列化组件

    2 序列化组件介绍 1. 序列化,序列化器会把模型对象(queryset,单个对象)转换成字典,经过response以后变成json字符串 2. 反序列化,把客户端发送过来的数据,经过request. ...

  2. Django框架(十九)—— drf:序列化组件(serializer)

    序列化组件 # 模型层 from django.db import modelsclass Book(models.Model): nid = models.AutoField(primary_key ...

  3. DRF的序列化——Serializers 序列化组件

    为什么要用序列化组件 当我们做前后端分离的项目~~ 我们前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式. 那么我们给前端数据的时候都要转成json格式,那就需要对我们从数据库 ...

  4. Django DRF认证组件/权限组件/序列化组件综合总结(完整版)

    本代码完成的功能是: 1.根据token判断用户登录状态,然后提示用户是否登陆, 2.用户登录后,根据用户类型判断用户是否有权限查看资料 使用rest_framework一定要在配置文件设置先设置 ' ...

  5. drf3 Serializers 序列化组件

    为什么要用序列化组件 做前后端分离的项目,我们前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式. 给前端数据的时候都要转成json格式,那就需要对从数据库拿到的数据进行序列化. ...

  6. APIView与序列化组件使用

    APIView基本使用 1.什么是APIView Django中视图views.py有两种一种是基于类的实现另一种是函数的实现,而APIView就是REST framework提供的所有视图的基类,继 ...

  7. Ajax 发送json格式数据以及发送文件(FormData)和自带的序列化组件: serializers

    前后端传输数据的编码格式(contentType) get请求数据就是直接放在url?后面的 url?usernmae=junjie&password=123... 可以向后端发送post请求 ...

  8. 快速上手Django(六) -Django之Django drf 序列化器Serializer类

    文章目录 快速上手Django(六) -Django之Django drf 序列化器Serializer类 1. 背景 2. 使用思路 3. 代码demo 4. [重要]序列化类 ModelSeria ...

  9. Django 基础(13)-Django drf 序列化器类to_representation和to_internal_value(处理返回的日期格式)、序列化类 ModelSerializer

    文章目录 一.Django drf 序列化 1. 背景 2. 使用思路 3. 代码demo 4. [重要]序列化类 ModelSerializer 5. DRF序列化器to_representatio ...

最新文章

  1. 2022-2028年中国汽车印制电路板(汽车PCB)产业深度调研及投资前景预测报告
  2. [转载] sql server 2000系统表解释
  3. ML:分类预测问题中评价指标(ER/混淆矩阵P-R-F1/ROC-AUC/RP/mAP)简介、使用方法、代码实现、案例应用之详细攻略
  4. 一张小票看透支付清结算架构
  5. sql每个月每个人的花销占比_星座月运(2020年12月),每个人开支花费大,得精打细算...
  6. HDU 2544 最短路(各种最短路算法的实现)
  7. max file descriptors_年轻族的战场!宋MAX强势对比嘉际
  8. 一月:你今年还回家过年吗?
  9. Apache Solr Velocity 注入远程命令执行漏洞复现 (CVE-2019-17558)
  10. 求1+2+3+...(信息学奥赛一本通-T1158)
  11. 关于高效、高质和高产
  12. 有关Silverlight TreeView组件的研究[2]——Silverlight学习笔记(7)
  13. DFS+剪枝:N个蛋放入M个篮子并可以任意取
  14. 大数据Hadoop学习记录(1)----HDFS目录和文件Shell操作
  15. 编译DPDK遇到make: *** /lib/modules/3.10.0-693.el7.x86_64/build: no such file or dirortory
  16. 计算机word文档无法工作,教您电脑word打不开怎么办
  17. tf.executing_eagerly()
  18. 微信小程序 - 小程序分享转发
  19. 电话交换机--程控交换机
  20. 项目怎么加入城市服务器,服务器奔溃逼疯玩家 模拟城市5或可加入单机模式

热门文章

  1. 2008年春晚视频锦集大全 在綫观看
  2. java nba2009,关于一个NBA球队连续夺冠的SQL查询问题,解法很精妙~
  3. 关于支付宝提现收费,这些误区和攻略你应该知道
  4. 聚氨酯无纺布的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  5. 分布式事务:本地事务与分布式事务
  6. Ubuntu空间不足解决,清理空间
  7. openwrt开机自启动
  8. 你思考问题的方式,决定你能走多远
  9. 了却布斯身后事,Youtube终弃Flash。新年爆竹辞魔鬼,奈何新任把命催。
  10. 南卡与JBL蓝牙耳机哪款比较好?数码资深玩家带你深度评测了解