drf-02-序列化器、数据验证(is_valid())、保存数据(create,save)、更新数据(update)、模型类序列化器、视图相关(APIView)

一、序列化器-Serializer

序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
反序列化,完成数据校验功能

1.定义序列化器

Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer
先创建一个新的子应用sers

python manage.py startapp sers

已有了一个数据库模型类students/Student

from django.db import models

# Create your models here.
class Student(models.Model):
    # 模型字段
    name = models.CharField(max_length=100,verbose_name="姓名",help_text="提示文本:账号不能为空!")
    sex = models.BooleanField(default=True,verbose_name="性别")
    age = models.IntegerField(verbose_name="年龄")
    class_null = models.CharField(max_length=5,verbose_name="班级编号")
    description = models.TextField(verbose_name="个性签名")

    class Meta:
        db_table="tb_student"
        verbose_name = "学生"
        verbose_name_plural = verbose_name

想为这个模型类提供一个序列化器,可以定义如下:

from rest_framework import serializers

# 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer
# 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
class StudentSerializer(serializers.Serializer):
    """学生信息序列化器"""
    #  需要进行数据转换的字段
    id = serializers.IntegerField()
    name = serializers.CharField()
    age = serializers.IntegerField()
    sex = serializers.BooleanField()
    description = serializers.CharField()

注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。 serializer是独立于数据库之外的存在。

常用字段类型

字段 字段构造方式
BooleanField BooleanField()
NullBooleanField NullBooleanField()
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)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(format=‘hex_verbose’) format: 1) 'hex_verbose’如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) ‘hex’ 如 “5ce0e9a55ffa654bcee01238041fb31a” 3)‘int’ - 如: “123456789012312313134124512351145145114” 4)‘urn’ 如: “urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a”`
IPAddressField IPAddressField(protocol=‘both’, unpack_ipv4=False, **options)
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)
DurationField DurationField()
ChoiceField ChoiceField(choices) choices与Django的用法相同
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)

选项参数:

参数名称 作用
max_length 最大长度
min_length 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
max_value 最大值
min_value 最小值

通用参数:

参数名称 说明
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用的验证器
error_messages 包含错误编号与错误信息的字典
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息
2.创建Serializer对象

Serializer的构造方法为:

Serializer(instance=None, data=empty, **kwarg)

说明:
1)序列化时,将模型类对象传入instance参数
2)反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如

serializer = AccountSerializer(account, context={'request': request})

通过context参数附加的数据,可以通过Serializer对象的context属性获取。

二、序列化器的使用

序列化器的使用分两个阶段:
  在客户端请求时,使用序列化器可以完成对数据的反序列化。
  在服务器响应时,使用序列化器可以完成对数据的序列化。

1.反序列化

1)数据验证(is_valid())

  使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
  在获取反序列化的数据前,必须调用is_valid() 方法进行验证,验证成功返回True,否则返回False。
  验证失败,可以通过序列化器对象的errors 属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
  验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。

定义序列化器,代码:

from rest_framework import serializers
class StudentSerializer(serializers.Serializer):
    # 需要转换的字段声明
    # 小括号里面声明主要提供给反序列化使用的
    name = serializers.CharField(required=True, max_length=20)
    age = serializers.IntegerField(max_value=150, min_value=0,required=True)
    sex = serializers.BooleanField(default=True)
    description = serializers.CharField(required=False,allow_null=True, allow_blank=True) #required=False,字段都可以不传递给后端,allow_null=True,允许提交过来的数据为空值(null--None),allow_blank=True 允许提交过来的数据为空字符串

通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证

# Create your views here.
from django.http import JsonResponse
from django.views import View
from .serializers import StudentSerializer
from students.models import Student
class StudentView(View):
    def post(self,request):
        """添加一个学生"""
        # 接受参数
        post_data = request.POST
        data = {
            "name":post_data.get('name'),
            "age":post_data.get('age'),
            "sex":post_data.get('sex'),
            "description":post_data.get('description'),
        }
        # 调用序列化器进行反序列化验证和转换
        serializer = StudentSerializer(data=data)
				serializer.errors  #查看错误信息
        
        # 当验证失败时,可以直接通过声明 raise_exception=True 让django直接跑出异常,那么验证出错之后,直接就再这里报错,程序中断了就
        
        result = serializer.is_valid(raise_exception=True)
        print( "验证结果:%s" % result )

        # 获取通过验证后的数据
        print( serializer.validated_data ) # form -- clean_data
        # 保存数据
        student = Student.objects.create(
            name=serializer.validated_data.get("name"),
            age=serializer.validated_data.get("age"),
            sex=serializer.validated_data.get("sex")
        )

        print(student)
        # 返回响应结果给客户端
        # alt + enter,可以实现快速导包
        return JsonResponse({"message": "ok"})

is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。

raise_exception参数
等于True会主动抛异常

serializer.is_valid(raise_exception=True)

全局钩子(validate)和局部钩子(validate_ )的使用

class StudentSerizlizer(serializers.Serializer):
    # 
    name = serializers.CharField(max_length=4,validators=[check666,])
    age = serializers.IntegerField(max_value=18)
    class_null = serializers.CharField()
    # description = serializers.CharField(required=False,allow_null=True)
    # required=False,allow_null=True允许字段为空,也就是不用传递过来这个data
    description = serializers.CharField(allow_blank=True)
    #allow_blank=True 允许只为空字符串

    # 局部钩子:针对单个属性对应的数据进行校验
    def validate_name(self,val):
        # print('xxxxx>>>',val) #xxxxx>>> ccbb
        if '777' in val:
            raise serializers.ValidationError('不能有777')
        return val #如果没有错误,需要return这个属性数据

    # 全局钩子: 主要是针对多个属性数据进行校验
    def validate(self,data):
        print(data) #OrderedDict([('name', 'c778'), ('age', 6), ('class_null', '1'), ('description', '123')])
        age = data.get('age')
        class_null = data.get('age')

        if age == class_null:
            raise serializers.ValidationError('age和class——null不能相等')

        return data  #如果没有错误,全局钩子要return所有数据

视图部分

def post(self,request):
        #
        print(request.POST)
        data = {
            'name':request.POST.get('name'),
            'age':request.POST.get('age'),
            'class_null':request.POST.get('class_null'),
            'description':request.POST.get('description'),
        }

        ser = StudentSerizlizer(data=data)

        if ser.is_valid():
            
            print(request.body)
            ret = models.Student.objects.create(
                **ser.validated_data
            )
    
            serializer = StudentSerizlizer(instance=ret)
            print(serializer.data)  #得到的是教研成功之后的所有正确数据
    
    
            return JsonResponse(serializer.data,safe=False,json_dumps_params={'ensure_ascii':False})
        # return JsonResponse({'xx':'xx'})

        else:
            return JsonResponse({'error':'有字段错误'})

执行顺序如下

# is_valid()方法时,先校验序列化器类中的所有属性Field(CharField(参数))参数对应的校验规则
# 再执行局部钩子
# 举例:比如有name和age两个属性,先执行name 的参数校验,在执行name的局部钩子(validate_name(self,val)),然后再执行age属性的参数校验,再执行age的局部钩子,最后所有属性的参数校验和局部钩子校验完成之后,执行全局钩子

# 最后执行全局钩子
2)保存数据(create,save)
方式1  直接在视图中保存

        if ser.is_valid():

            # print(request.body)
            ret = models.Student.objects.create(
                **ser.validated_data
            )
            
            serializer = StudentSerizlizer(instance=ret)

            return JsonResponse(serializer.data,safe=False,json_dumps_params={'ensure_ascii':False})

        else:
            print(ser.errors)
            return JsonResponse({'error':'有字段错误'})


方式2
在序列化器中定义create方法来数据的保存
class StudentSerizlizer(serializers.Serializer):
    # 
    name = serializers.CharField(max_length=4,validators=[check666,])
 	...
    
    def create(self, validated_data):

        # self.validated_data
        # validated_data
        # print('>>',self.validated_data)
        print('>>',validated_data)
        ret = models.Student.objects.create(
            **validated_data
        )
        return ret

视图中通过save方法来触发序列化器类中的create方法

        if ser.is_valid():

            instance = ser.save()  #得到create方法的返回值
            serializer = StudentSerizlizer(instance=instance)

            return JsonResponse(serializer.data,safe=False,json_dumps_params={'ensure_ascii':False})
            # return JsonResponse({'xx':'xx'})
3)更新数据(update)
在序列化器中定义update方法来数据的更新
class StudentSerizlizer(serializers.Serializer):
    # 
    name = serializers.CharField(max_length=4,validators=[check666,])
 	...
    # 做更新动作
    def update(self, instance, validated_data):

        # print(instance)
        # print(validated_data)
        instance.name = validated_data['name']
        instance.age = validated_data['age']
        instance.class_null = validated_data['class_null']
        instance.description = validated_data['description']
        instance.save()
        return instance

视图
	   def put(self,request):

        data = {
            'id': 2,
            'name':'xx',
            'age':8,
            'sex':0,
            'class_null':'9',
            'description':'xx',

        }
        obj = models.Student.objects.get(id=data.get('id'))
        s_obj = StudentSerizlizer(instance=obj,data=data)  # 实例化序列化器类时,传入instance参数
        if s_obj.is_valid():
            s_obj.save()  #触发序列化器类的update方法

        else:
            return JsonResponse({'error':'数据错误'})
4)read_only和write_only参数的区别
from rest_framework import serializers

class StudentSerizlizer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    # read_only=True,序列化时序列化出该字段数据,反序列化校验时不要校验这个数据
    name = serializers.CharField(max_length=4,)

    age = serializers.IntegerField(max_value=18,write_only=True)
    # write_only=True,序列化时不序列化这个字段数据,反序列校验时,需要客户端传递这个数据过来进行校验
    class_null = serializers.CharField()

    description = serializers.CharField(allow_blank=True)

视图部分

from django.shortcuts import render
from django.views import View
# Create your views here.
from students import models
from .serializers import StudentSerizlizer
from django.http import JsonResponse
class StudentView(View):

    def get(self,request):
        all = models.Student.objects.all()
        serializer = StudentSerizlizer(instance=all, many=True)

        return JsonResponse(serializer.data, safe=False, json_dumps_params={'ensure_ascii':False})

    def post(self,request):

        print(request.POST)

        data = {
            'name':request.POST.get('name'),
            'sex':request.POST.get('sex'),
            'age':request.POST.get('age'),
            'class_null':request.POST.get('class_null'),
            'description':request.POST.get('description'),
        }
        serializer = StudentSerizlizer(data=data)
        serializer.is_valid()
        print(serializer.errors)
        print('正确数据:',serializer.validated_data)


        return JsonResponse({'xx':'xx'})
5)partial参数:默认为False
   def put(self,request):
        data = {
            'name':'chao',
            'age':18
        }
        serializer = StudentSerizlizer(data=data,partial=True)
        # partial=True:只需要校验传入给序列化器的数据,适用于部分数据更新
        serializer.is_valid()
        print(serializer.errors)
        print('正确数据:', serializer.validated_data)
        
        return JsonResponse({'ss': 'kk'})

三、模型类序列化器modelSerializer的使用

模型类序列化器来快速创建一个Serializer类。
ModelSerializer与常规的Serializer相同,但提供了:

  • 基于模型类自动生成一系列字段
  • 基于模型类自动为Serializer生成validators,比如unique_together
  • 包含默认的create()和update()的实现

定义如下的类

from rest_framework import serializers
from students import models
class StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Student
        fields = '__all__'
        # fields =  ['id', 'name', 'age']
        # fields =  ['id', 'name', 'age']
        # exclude = ['name','age']
        extra_kwargs = {
            'id':{'read_only':True,},
            'age':{'write_only':True,}
        }

        '''
            id
            name = models.CharField(max_length=100,verbose_name="姓名",help_text='提示文本:不能为空')
            sex = models.BooleanField(default=1,verbose_name="性别")
            age = models.IntegerField(verbose_name="年龄")
            class_null = models.CharField(max_length=5,verbose_name="班级编号")
            description = models.TextField(max_length=1000,verbose_name="个性签名")
        
        '''
        '''
                id = serializers.IntegerField(read_only=True)
                name = serializers.CharField(max_length=6,)  # name char(6)
                age = serializers.IntegerField(max_value=18,write_only=True)
                sex = serializers.BooleanField()
                class_null = serializers.CharField()
                description = serializers.CharField(allow_blank=True)
        
        '''

视图当中使用

from django.shortcuts import render
from django.http import JsonResponse
# Create your views here.
from django.views import View
from .serializers import StudentModelSerializer
from students import models
class StudentView(View):

    def get(self,request):
        all = models.Student.objects.all()

        model_ser = StudentModelSerializer(instance=all,many=True)
        print()

        return JsonResponse(model_ser.data, safe=False, json_dumps_params={'ensure_ascii':False})

    def post(self,request):
        print(request.POST)
        obj = StudentModelSerializer(data=request.POST)

        if obj.is_valid():
            print(obj.validated_data)
            obj.save()  #自动能够帮我们进行数据保存
            return JsonResponse({'msg':'success'})
        print(obj.errors)
        print(obj.validated_data)
        return JsonResponse({'xx':'ssssss'})

四、视图相关

1.视图

  drf除了在数据序列化部分简写代码以外,还在视图中提供了简写操作。所以在django原有的django.views.View类基础上,drf封装了多个子类以供使用。
Django REST framwork 提供的视图的主要作用:

  • 控制序列化器的执行(检验、保存、转换数据)
  • 控制数据库查询的执行
  • 调用请求类和响应类

APIView视图简单使用

view.py

from django.shortcuts import render

# Create your views here.
from django.shortcuts import HttpResponse
from django.views import View

from rest_framework.views import APIView
from rest_framework.response import Response

"""drf提供的请求和响应类只能在drf封装过的子视图类中使用,也就是说不能再django.view.View中使用
    只要类视图直接或者间接继承了APIView,则视图方法中使用的request,就是rest_framework.request.Request,同时,只有在APIVIew的子视图类中才可以使用rest_framework.respone.Response
"""
class StudentAPIView(APIView):
# class StudentAPIView(View):  #之前的写法
    def get(self,request):
        print(request)
        #
        return Response({'msg':'ok'})
        # return HttpResponse('ok')

urls.py

from django.urls import path
from . import views
urlpatterns = [
    path(r'students/',views.StudentAPIView.as_view()),

]

总路由中

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    ...
    path('req/',include('req.urls')),
]

启动项目,用Postman访问看到如下效果:

drf-02-序列化器、数据验证(is_valid())、保存数据(create,save)、更新数据(update)、模型类序列化器、视图相关(APIView)_第1张图片
2.request对象
from rest_framework.views import APIView

class UserView(APIView):

    def get(self,request):
        print(request.GET)
        print(request.query_params)
		# request.GET和request.query_params是等价的

        return JsonResponse({'xx':'xxxxx'})



    def post(self,request):
        print(request)
        # 当发送的数据格式为..urlencoded类型时,request.POST和request.data等价
        # print(request.POST.getlist('hobby')) #
        # 当发送过来的是json类型数据时,我们使用request.data属性能够获取到数据
        print(request.data) #{'username': 'xxxx', 'password': '123'},普通字典类型
        # request.data能够获取到客户端发送过来的json类型数据,但是得到的结果为普通字典类型,但是如果是多选数据,不能使用getlist方法获取

        return JsonResponse({'xx': 'xxxxx'})

1).data

request.data 返回解析之后的请求体数据。类似于Django中标准的request.POST和 request.FILES属性,但提供如下特性:

  • 包含了解析之后的文件和非文件数据
  • 包含了对POST、PUT、PATCH请求方式解析后的数据
  • 利用了REST framework的parsers解析器,不仅支持表单类型数据(urlencoded,form-data),也支持JSON数据(application/json)

2).query_params

request.query_params与Django标准的request.GET相同,只是更换了更正确的名称而已。

3.response对象
查看drf的默认配置
from rest_framework import settings

引入response
from rest_framework.response import Response

Response默认响应的是json数据类型

当用浏览器访问时看到页面效果.


用户配置替换drf内部配置的写法
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览器API渲染器
    )
}

response的方法的相关参数

Response(data, status=None, template_name=None, headers=None, content_type=None)

参数说明:

  • data: 为响应准备的序列化处理后的数据;
  • status: 状态码,默认200;
  • template_name: 模板名称,如果使用HTMLRenderer 时需指明;就是有些人觉得Response返回的那个页面丑,那么就可以通过这个模板自行定制。
  • headers: 用于存放响应头信息的字典;比如放一些cookie啊或者一些自定制的响应头啊都可以,例如:return Response({‘msg’: ‘ok’},status=204,headers={‘xx’:‘oo’})
  • content_type: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据(accept请求头)来设置该参数。
4.响应状态码
from rest_framework import status

# return Response({'xx':'xxxxx'}, status=201)
return Response({'xx':'xxxxx'}, status=status.HTTP_201_CREATED)

所有状态码

HTTP_100_CONTINUE = 100
HTTP_101_SWITCHING_PROTOCOLS = 101
HTTP_200_OK = 200
HTTP_201_CREATED = 201
HTTP_202_ACCEPTED = 202
HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203
HTTP_204_NO_CONTENT = 204
HTTP_205_RESET_CONTENT = 205
HTTP_206_PARTIAL_CONTENT = 206
HTTP_207_MULTI_STATUS = 207
HTTP_208_ALREADY_REPORTED = 208
HTTP_226_IM_USED = 226
HTTP_300_MULTIPLE_CHOICES = 300
HTTP_301_MOVED_PERMANENTLY = 301
HTTP_302_FOUND = 302
HTTP_303_SEE_OTHER = 303
HTTP_304_NOT_MODIFIED = 304
HTTP_305_USE_PROXY = 305
HTTP_306_RESERVED = 306
HTTP_307_TEMPORARY_REDIRECT = 307
HTTP_308_PERMANENT_REDIRECT = 308
HTTP_400_BAD_REQUEST = 400
HTTP_401_UNAUTHORIZED = 401
HTTP_402_PAYMENT_REQUIRED = 402
HTTP_403_FORBIDDEN = 403
HTTP_404_NOT_FOUND = 404
HTTP_405_METHOD_NOT_ALLOWED = 405
HTTP_406_NOT_ACCEPTABLE = 406
HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407
HTTP_408_REQUEST_TIMEOUT = 408
HTTP_409_CONFLICT = 409
HTTP_410_GONE = 410
HTTP_411_LENGTH_REQUIRED = 411
HTTP_412_PRECONDITION_FAILED = 412
HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413
HTTP_414_REQUEST_URI_TOO_LONG = 414
HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416
HTTP_417_EXPECTATION_FAILED = 417
HTTP_418_IM_A_TEAPOT = 418
HTTP_422_UNPROCESSABLE_ENTITY = 422
HTTP_423_LOCKED = 423
HTTP_424_FAILED_DEPENDENCY = 424
HTTP_426_UPGRADE_REQUIRED = 426
HTTP_428_PRECONDITION_REQUIRED = 428
HTTP_429_TOO_MANY_REQUESTS = 429
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451
HTTP_500_INTERNAL_SERVER_ERROR = 500
HTTP_501_NOT_IMPLEMENTED = 501
HTTP_502_BAD_GATEWAY = 502
HTTP_503_SERVICE_UNAVAILABLE = 503
HTTP_504_GATEWAY_TIMEOUT = 504
HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505
HTTP_506_VARIANT_ALSO_NEGOTIATES = 506
HTTP_507_INSUFFICIENT_STORAGE = 507
HTTP_508_LOOP_DETECTED = 508
HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509
HTTP_510_NOT_EXTENDED = 510
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511
5.template_name

用于自定制浏览器的响应页面,了解

6.headers

定制响应头键值对

 return Response({'xx':'xxxxx'}, status=status.HTTP_201_CREATED,headers={'xx':'oo'})

你可能感兴趣的:(7DRF,drf,serializer,序列化器,APIView)