day72:drf:反序列化功能&模型类序列化器Modelserializer&drf视图APIView

目录

1.续:反序列化功能(5-8)

  1.用户post类型提交数据,反序列化功能的步骤

  2.反序列化功能的局部钩子和全局钩子

    局部钩子和全局钩子在序列化器中的使用

    反序列化相关校验的执行顺序

  3.反序列化的数据保存功能

  4.反序列化的数据更新功能

  5.Field字段参数:read_only和write_only

  6.Field字段参数:partial参数

2.模型类序列化器的使用:Modelserializer

  1.Modelserializer的简单介绍

  2.Modelserializer的使用

3.drf:视图相关

  1.APIView

  2.APIView中的request

  3.APIView中的response

1.续:反序列化功能(5-8)

前文:反序列化功能

用户post类型提交数据,反序列化功能的步骤

class Student(View):
    def get(self,request):
        ...
        
    def post(self,request):
        '''1.获取用户在前端输入的数据'''
        recv_data = {
            'name':request.POST.get('name'),
            'age':request.POST.get('age'),
            'class_null':request.POST.get('class_null'),
            'description':request.POST.get('description'),
        }
        '''2.实例化序列化器类,生成序列化器类对象,并将我们获取的数据传进去完成对数据的反序列化'''
        ser = StudentSerizlizer(data=recv_data)
        
        '''3.校验,全部通过得到True,一个字段错了都是得到False'''
        print(ser.is_valid()) 
        
        '''4.所有字段的错误信息'''
        print(ser.errors) 
        
        '''---------------------------------------------------------------'''
        
        '''5.反序列化完成之后的数据'''
        print(ser.validated_data) 
        
        '''6.将反序列化后的数据添加到数据库中'''
        ret = models.Student.objects.create(
            **ser.validated_data
        )
        
        '''7.反序列化的数据已经存储到数据库中,但是现在需要前端显示出我们新添加的数据'''
        '''按照接口规范:如果post请求提交保存了一条记录,那么要将新添加的数据再响应回去'''
        serializer = StudentSerializer(instance=ret)
        print(serializer.data) # 序列化完成后的数据
        
        '''8.将序列化完成后的数据返回给前端,并设置safe和ensure_ascii参数'''
        return JsonResponse(serializer.data,safe=False,json_dumps_params={"ensure_ascii":False})

反序列化功能的局部钩子和全局钩子

1.局部钩子和全局钩子在序列化器中的使用

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

    '''局部钩子:针对单个属性对应的数据进行校验'''
    def validate_name(self,val):# val就是你对应字段的内容,函数名固定写法:validate_字段名
        if '777' in val:
            raise serializers.ValidationError('不能有777')
        return val # 如果没有错误,需要return这个属性数据

    
    '''全局钩子: 主要是针对多个属性数据进行校验'''
    def validate(self,data):
        
        '''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所有数据

2.反序列化相关校验的执行顺序

举个例子,代码如下所示

class StudentSerizlizer(serializers.Serializer):
    
    # 1.字段限制
    name = serializers.CharField(max_length=4,validators=[check666,])
    age = serializers.IntegerField(max_value=18)
    
    # 2.局部钩子
    def validate_name(self,val):
           pass
     
    def validate_age(self,val):
           pass
        
    # 3.全局钩子
    def validate(self,data):
           pass

执行顺序:

  1.先执行name中CharField参数中的规则

  2.执行name的局部钩子函数

  3.执行age的IntegerField参数中的规则

  4.执行age的局部钩子函数

  5.执行全局钩子函数

Tip:is_valid中的raise_exception参数

serializer.is_valid(raise_exception=True) # 等于True会主动抛出异常

反序列化的数据保存功能

反序列化的数据保存,一共有两种方式:

方式一:直接在视图中保存

# 方式1:直接在视图中保存

class StudentView(View): def post(self,request): if ser.is_valid(): 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':'有字段错误'})

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

# 方式2 save+create

# 在序列化器中定义create方法来数据的保存 class StudentSerizlizer(serializers.Serializer): name = serializers.CharField(max_length=4,validators=[check666,]) age = serializers.IntegerField(max_value=18) ...... def create(self, validated_data): # 定义create方法 '''self.validated_data和validated_data结果是相同的,所以直接用validated_data即可''' print(validated_data) ret = models.Student.objects.create( **validated_data ) return ret # 视图中通过save方法来触发,序列化器类中的create方法 class StudentView(View): def post(self,request): if ser.is_valid(): '''通过save()方法去触发序列化器中的create方法''' instance = ser.save() # 得到create方法的返回值 serializer = StudentSerizlizer(instance=instance) return JsonResponse(serializer.data,safe=False,json_dumps_params={'ensure_ascii':False})

反序列化的数据更新功能

# 在序列化器中定义update方法来数据的更新
class StudentSerizlizer(serializers.Serializer):

    name = serializers.CharField(max_length=4,validators=[check666,])
    age = serializers.IntegerField(max_value=18)
     ...
    
    # 做更新动作
    def update(self, instance, validated_data):
        '''instance,validated_data?????'''
        print(instance) # id=2 的模型类对象
        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

# 视图部分
class StudentView(View):
    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'))
        
        '''instance=obj用来指定这个save()触发的是序列化器中的update方法,而不是create方法,data就是你要更新的数据'''
        s_obj = StudentSerizlizer(instance=obj,data=data)
        
        '''判断反序列化之后的数据是否合法'''
        if s_obj.is_valid():
            s_obj.save()  # 触发序列化器类的update方法

        else:
            return JsonResponse({'error':'数据错误'})
    

Field字段参数:read_only和write_only

read_only和write_only是field字段里面的参数,也是用来对字段做限制的

from rest_framework import serializers

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

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

    description = serializers.CharField(allow_blank=True)

视图部分这样写:

from django.shortcuts import render
from django.views import View
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'})

Field字段参数:partial参数

partial参数默认为False,若partial=True则代表只需要校验传入给序列化器的数据(data),其他的字段不校验.适用于部分数据更新

应用场景:

比如在序列化器中加入定义了五个字段。

如果用户在前端提交数据时,必须要将五个字段都提交,否则就会报错。

但是在现实应用场景下,有很多情况是不需要将五个字段全部提交的。比如数据更新

这个时候想要更改,但是序列化器的代码已经成型了,不太好进行修改。 【eg:提交需要提交5个字段,更新提交2个字段】

class StudentView(View):
    def put(self,request):
        
        '''要更新的数据'''
        data = {
            'name':'chao',
            'age':18
        }
        
        '''partial=True:只需要校验传入给序列化器的数据(data),其他的字段不校验.适用于部分数据更新'''
        serializer = StudentSerizlizer(data=data,partial=True)
        serializer.is_valid()
        print(serializer.errors)
        print('正确数据:', serializer.validated_data)
        
        return JsonResponse({'ss': 'kk'})

模型类序列化器的使用:Modelserializer

1.Modelserializer的简单介绍

如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

ModelSerializer与常规的Serializer相同,但提供了:

  • 基于模型类自动生成一系列字段

  • 基于模型类自动为Serializer生成validators,比如unique_together

  • 包含默认的create()和update()的实现

2.Modelserializer的使用

models.py 

....

serializers.py

from rest_framework import serializers
from students.models import Student
class StudentModelSerializer(serializers.ModelSerializer):

    # 如果模型类序列化器,必须 1.声明本次调用是哪个模型,2.模型里面的哪些字段
    class Meta:
        model = Student
        fields = ["id","name","age","description","sex"]
        # fields = "__all__" # 表示操作模型中的所有字段
        
        # 添加额外的验证选项
        exclude = ['id',] # 排除字段
        extra_kwargs = {
            "sex":{"write_only":True,},
            "id":{"read_only":True,}
        }

views.py

class StudentViewSet(View):

    def post(self,request):

        data = request.POST
        serializers = StudentsSerializer(data=data)

        status = serializers.is_valid()
        
        student = serializers.save()  # 上面使用的ModelSerializer,所以不需要我们自己写create方法了
        print(student)
        return JsonResponse({'msg':'henhao'})

drf:视图相关

1.APIView

原来的视图都是继承View类

class StudentView(View):
    def get:
        pass
    ......

而drf提供了一个APIView,如下所示

from django.shortcuts import render
from django.shortcuts import HttpResponse
from django.views import View
from rest_framework.views import APIView
from rest_framework.response import Response

"""
1.drf提供的请求和响应类只能在drf封装过的子视图类中使用,也就是说不能再django.view.View中使用

2.只要类视图直接或者间接继承了APIView,则视图方法中使用的request,就是rest_framework.request.Request,同时,只有在APIVIew的子视图类中才可以使用rest_framework.respone.Response
"""
class StudentAPIView(APIView):
# class StudentAPIView(View):  #之前的写法
    def get(self,request):
        
        print(request)
        # <rest_framework.request.Request object at 0x11d733e90>
        
        return Response({'msg':'ok'})

2.APIView中的request

REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。

REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。这里我们可以自行写一个接口测试一下django原来的模式是解析不了json数据的,drf可以解析。但是需要注意的是:客户端如果传递过来的是json数据,那么request.data获取到的字典类型数据,不是querydict类型,也就没有了getlist方法,多选的数据,通过get就能取出来。

Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。

无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。

from rest_framework.views import APIView

class UserView(APIView):

    def get(self,request):
        '''当我们访问http://127.0.0.1:8001/req/students/?age=100'''
        print(request.GET) # <QueryDict: {'age': ['100']}>
        print(request.query_params) # <QueryDict: {'age': ['100']}>
        # request.GET和request.query_params是等价的

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

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

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

3.APIView中的response

1.response介绍

REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。

我们后端如果通过Response来想用数据时,通过postman发送get请求获取数据,你会发现得到的是纯json数据,但是通过浏览器访问时会的到一个页面。这是为什么呢?drf的APIView在响应内容的时候会自动通过请求头中的浏览器信息来进行数据的回复(Response),如果是浏览器,那么返回的就是个页面(当然我们也可以不让他返回页面,可设置的,后面说)如果不是浏览器,给你返回的就是纯json数据。这是由drf中配置的两个不同的响应类产生的效果,看下面的配置。

REST framework提供了Renderer 渲染器,用来根据请求头中的Accept(客户端希望接收的数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。

# 查看drf的默认配置
from rest_framework import settings

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

2.response参数解释

# 引入Response
from rest_framework.response import Response


    # response里面的相关参数
    return Response({},status=201,template_name=None,headers=None,content_type=None)
'''
{}:响应的数据...
status:状态码
template:用于自定义浏览器的响应页面
headers:自定义响应头键值对
content_type:....

'''

参数说明:

  • 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请求头)来设置该参数。

3.状态码大全

# 查看所有状态码
from rest_framework import status

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

Tip:响应状态码的两种书写方式

from rest_framework import status

# 响应状态码方式一
return Response({'xx':'xxxxx'}, status=201)

# 响应状态码方式二
return Response({'xx':'xxxxx'}, status=status.HTTP_201_CREATED)

 

posted @ 2020-10-21 17:43  iR-Poke  阅读(263)  评论(0编辑  收藏  举报