drf序列化类的介绍及使用

【一】关于HTTP请求的补充

#
"""request.POST请求必须是post请求且是urlencoded的编码格式的数据才能拿到数据"""
​
#1.http请求不同编码格式,请求体什么样子?重要
    -urlencoded:在请求体中是--》b'id=1&name=llh'
    -json:在请求体中是json--b'{"name":"lqz","age":19}'
        -form-data: 随机字符串asdfasdf-------数据部分  随机字符串asdfasdfasdf-----文件部分
            eg:
                b'----------------------------876677566299917579045132\r\nContent-Disposition: form-data; name="id"\r\n\r\n1\r\n----------------------------876677566299917579045132\r\nContent-Disposition: form-data; name="myfile"; filename="1.txt"\r\nContent-Type: text/plain\r\n\r\n1\r\n----------------------------876677566299917579045132--\r\n'
    
    
​
#2.get请求能不能在请求体中携带数据?
    -能,只能在request.body里取不能在request.POST里取他取不到东西
    -但是一般都是post或put请求在请求体中带数据
​
#3.get请求和post请求的区别?
​
​
总结:
    -1.request.POST请求必须是post请求且是urlencoded的编码格式的数据才能拿到数据
    -2.request.GET:请求地址栏中url链接的参数?后面的:这些请求都能拿到get,post,delete,put
            request.GET---><QueryDict: {'key': ['key', '99']}>
                -类字典:取出key的值
                    -只取一个:request.GET.get('key')
                    -两个都取:request.GET.getlist('key')
    -3.request.body:无论什么请求, 无论什么编码格式,都在里面

【二】新的Request对象和Response

2.1Request

#1.以后全是cbv,继承的是drf的APIView--->它也继承django的View及子类
#2.DRF提供了Response类,这是专门设计来生成HTTP响应的,并且可以与DRF的各种特性,继承APIView后,以后响应同意用drf的Response
​
#3.APIView中的request请求对象
    -1.request请求对象:http请求的所有内容,都会在这个对象中
    
    -2.继承APIView后的request对象和原来的request对象不是同一个
        -原来是:<class 'django.core.handlers.wsgi.WSGIRequest'>
        -继承之后是:<class 'rest_framework.request.Request'>
            
    -3.但是用法与原来的request对象相同,都有如下方法而且,得到的结果一样
            print(request.method)//GET
            print(request.POST)//<QueryDict: {}>
            print(request.GET)//<QueryDict: {}>
            print(request.get_full_path())// /api/v3/index/
            
   -4.有一样的肯定也有不一样升级的地方
        -4.1request.body不同,原来的request对象可以直接取出请求中原生的请求体数据,位置在哪无所谓,但是现在新的一定要是写在是在其他request.的第一个要不然会报django.http.request.RawPostDataException: You cannot access body after reading from request's data stream)
        """如果之前已经有request.POST或request.PUT就会,由于数据流只能被读取一次,可能在POST取后,那个数据已经变了一种格式了"""
        -4.2.在继承APIView的request对象中,可以利用request.data,无论哪种编码格式,请求体的数据,都在这里面
            -urlencoded,form-data:是QueryDict的对象
                form-data:<QueryDict: {'id': ['1'], 'myfile': [<InMemoryUploadedFile: 1.txt (text/plain)>]}>
                urlencoded:<QueryDict: {'id': ['1'], 'name': ['llh']}> 
            -json:是普通字典对象{'detail': 'q.'}
            -但是,都当字典用即可
request_data就是一个字典   
    -5.request.FILES新旧相同
            -前端传的文件从这里取
            新/旧:<MultiValueDict: {'myfile': [<InMemoryUploadedFile: 1.txt (text/plain)>]}>
                
    -6.request.query_params # restful规范的过滤条件(就是问号后面)的查询参数
            -request.GET
        eg:<QueryDict: {'name': ['llh']}>
     

2.2Response

# 1.from rest_framework.response import Response
​
#2.怎么用? 
    -1 直接放字典,列表或字符串
        Response('ok')这个ok是放在了响应体里了
#3.如何放状态码?Response('ok',status=200)
#4.如何放响应头?Response('ok',status=200,headers={k:v})
​
#5.总结
data=None # 响应体:可以传 字典,列表或字符串body
status=None# http响应 状态码--》drf封装了所有常量   HTTP_200_OK = 200        
template_name=None# 忽略掉--》指定使用浏览器访问返回的模板,没写用默认模板,如果要用记得要去注册一下
headers=None # 响应头           
exception=False# 异常
content_type=None # 响应编码格式,一般不动,都用json

【三】 序列化类介绍

# 序列化类的作用?
    -前端传json格式字符串 给 后端 --》后端需要 保存到数据库---》反序列化
    -后端从数据库查出来的 对象---》以json格式字符串的形式给前端--》序列化
    
    -serializer就是为了完成上面的操作
        序列化
        反序列化
        反序列化校验

【四】序列化类快速使用

4.1快速使用

"""
使用步骤:
    1 定义一个类,继承Serializer
    2 在类中写要序列化的字段:字段类,跟models中得一一对应
    3 在视图类中使用三步走
        # 1 查出对象
        obj = Student.objects.filter(pk=pk).first()
        # 2 序列化
        serializer = StudentSerializer(instance=obj)
        # 3 返回
        return Response(serializer.data)
"""
​
1.view.py
class StudentView(APIView):
    def get(self,request):
        obj=Student.objects.all()
        serializer=StudentSerializer(instance=obj,many=True)
        return Response(serializer.data)
2.models.py
from django.db import models
​
# Create your models here.
class Student(models.Model):
    name=models.CharField(max_length=30)
    age=models.IntegerField()
    gender=models.IntegerField(choices=((1,'男'),(2,'女'),(0,'未知')),default=1,)
3.serializers.py
from rest_framework import serializers
​
​
class StudentSerializer(serializers.Serializer):
    id=serializers.IntegerField()
    name=serializers.CharField()
    age=serializers.IntegerField()
    gender=serializers.IntegerField()

4.2常用字段类

# 1 记住--》跟models中得 model.字段类, 一一对应
# 2 具体有哪些--了解
BooleanField
NullBooleanField    
CharField  #    
EmailField  
RegexField  
SlugField   
URLField    
UUIDField   
IPAddressField
IntegerField      #  
FloatField
DecimalField    
DateTimeField  #    
DateField     #
TimeField     #
ChoiceField 
MultipleChoiceField 
FileField   
ImageField  
# --------两个特殊的,后面讲,很重要----
ListField
DictField   
# 3 大绝招:如果不知道models和Serializer如何对应
    序列化类统一用 CharField 

4.3常用字段参数

# 1 序列化的 字段类在实例化时,传参数
    -作用是:为了反序列化校验用
    
# 2 有哪些字段参数--》了解
    # 只针对于:CharField
    max_length  最大长度
    min_lenght  最小长度
    allow_blank 是否允许为空
    trim_whitespace 是否截断空白字符
    
    # 只针对于:IntegerField
    max_value   最小值
    min_value   最大值
    
    # 只针对于:DateTimeField 
    format:序列化时,显示的格式
    DateTimeField(format='Y-m-d')
    
    # 所有字段类都用
    required:是否必填   
    default :反序列化时使用的默认值
    allow_null  表明该字段是否允许传入None,默认False
​
    
# 3 两个重点-先不讲
    read_only   表明该字段仅用于序列化输出,默认False
    write_only  表明该字段仅用于反序列化输入,默认False

【五】反序列化保存

5.1新增

#1.view.py
    def post(self,request):
        print()
        serializer=StudentSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response({"code":201,"msg":serializer.errors})
#2.serializer
class StudentSerializer(serializers.Serializer):
    id=serializers.IntegerField(required=False)
    name=serializers.CharField(required=True)
    age=serializers.IntegerField(required=True)
    gender=serializers.IntegerField(required=False,default=0)
    # 不重写会报错在baseSerializer有一个save方法--》里有update
    #        def create(self, validated_data):
    #         raise NotImplementedError('`create()` must be implemented.')
    def create(self, validated_data):
        student=Student.objects.create(**validated_data)
        #         if self.instance is not None:
        #             self.instance = self.update(self.instance, validated_data)
        #             assert self.instance is not None, (
        #                 '`update()` did not return an object instance.'
        #             )必须要有返回值否则就断言报错
        return student
    
 #3.models.py
class Student(models.Model):
    name=models.CharField(max_length=30)
    age=models.IntegerField()
    gender=models.IntegerField(choices=((1,'男'),(2,'女'),(0,'未知')))

5.2更新

#1.views.py 
    def put(self, request,book_id):
        obj = Student.objects.filter(pk=book_id).first()
        if obj:
            serializer=StudentSerializer(instance=obj,data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
        return Response({"code": 201, "msg": "修改失败"})
#2.serializer
    def update(self, instance, validated_data):
        print(instance)#是一个对象Student object (1)
        print(validated_data)#是一个字典{'name': '阿1', 'age': 2, 'gender': 0}
        for key in validated_data:
            # key是一个字符串,字符串和对象就可以想到反射
            setattr(instance,key,validated_data[key])
        return instance

5.3关于修改和更新的源码

1.执行serializer.save()--->StudentSerializer类中没用--》所以去他的父类里面找Serializer--》还是没有--》去爷爷类找BaseSerializer--》发现有save()
2.观察save()
"""     发现1:他是通过判断self.instance有没有值来判断是更新还是修改
        发现2:至于为什么一定要返回instance呢,因为最后一句是要返回的,然后如果不给self.instance值那么,就会报错"""
        if self.instance is not None:
            self.instance = self.update(self.instance, validated_data)
            assert self.instance is not None, (
                '`update()` did not return an object instance.'
            )
        else:
            self.instance = self.create(validated_data)
            assert self.instance is not None, (
                '`create()` did not return an object instance.'
            )
​
        return self.instance
3.观察update和create
"""发现1:update必须有两个形参,create是一个
   发现2:如果不去重写实现update和create会主动抛出异常"""
    def update(self, instance, validated_data):
        raise NotImplementedError('`update()` must be implemented.')
​
    def create(self, validated_data):
        raise NotImplementedError('`create()` must be implemented.')
​

1.把学生的5个接口写完,使用序列化类

#1.views
from rest_framework.response import Response
from rest_framework.views import APIView
​
from app03.models import Student
from app03.serializer import StudentSerializer
# Create your views here.
class StudentView(APIView):
    def get(self,request):
        obj=Student.objects.all()
        if obj:
            serializer=StudentSerializer(instance=obj,many=True)
            return Response(serializer.data)
        return Response({"code": 201, "msg": "查询失败"})
    def post(self,request):
        serializer=StudentSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response({"code":201,"msg":serializer.errors})
​
​
class StudentDetailView(APIView):
    def get(self, request,book_id):
        obj=Student.objects.filter(pk=book_id).first()
        if obj:
            serializer=StudentSerializer(instance=obj,many=False)
            return Response(serializer.data)
        return Response({"code": 201, "msg": "查询失败"})
​
    def put(self, request,book_id):
        obj = Student.objects.filter(pk=book_id).first()
        if obj:
            serializer=StudentSerializer(instance=obj,data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
        return Response({"code": 201, "msg": "修改失败"})
    def delete(self, request,book_id):
        obj = Student.objects.filter(pk=book_id).first()
        if obj:
            Student.objects.filter(pk=book_id).delete()
            return Response(status=200)
        return Response({"code": 201, "msg": "查询失败"})
#2.models
from django.db import models
​
# Create your models here.
class Student(models.Model):
    name=models.CharField(max_length=30)
    age=models.IntegerField()
    gender=models.IntegerField(choices=((1,'男'),(2,'女'),(0,'未知')))
​
#3.serializer.py
from rest_framework import serializers
from app03.models import Student
class StudentSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    name = serializers.CharField(required=True)
    age = serializers.IntegerField(required=True)
    gender = serializers.IntegerField(required=False, default=0)
​
    # 不重写会报错在baseSerializer有一个save方法--》里有update
    #        def create(self, validated_data):
    #         raise NotImplementedError('`create()` must be implemented.')
    def create(self, validated_data):
        student = Student.objects.create(**validated_data)
        #         if self.instance is not None:
        #             self.instance = self.update(self.instance, validated_data)
        #             assert self.instance is not None, (
        #                 '`update()` did not return an object instance.'
        #             )必须要有返回值否则就断言报错
        return student
​
    def update(self, instance, validated_data):
        print(instance)#是一个对象Student object (1)
        print(validated_data)#是一个字典{'name': '阿1', 'age': 2, 'gender': 0}
        for key in validated_data:
            # key是一个字符串,字符串和对象就可以想到反射
            setattr(instance,key,validated_data[key])
        return instance
​
    
"""注意要汉化错误信息在setting里改
LANGUAGE_CODE = 'zh-hans'
​
# 时区 UTC 国际时区
# 本地时区 中国时区在亚洲上海
# Asia/Shanghai
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'
​
USE_I18N = True
​
USE_L10N = True
​
USE_TZ = False
    """

2.编写一个装饰器,装在fbv上,让原生django的request对象,具备跟drf的request一样的data功能

from functools import wraps
# Create your views here.
# 装饰器
def outter(func):
    @wraps(func)
    def inner(request,*args,**kwargs):
        data=json.loads(request.body)
        # print(data)
        # print(type(data))
        # 因为request是对象,对象和字符串
        setattr(request,'data',data)
        return func(request,*args,**kwargs)
    return inner
@outter
def index(request):
    print(request.data)
    obj = Books2.objects.all()
    books_list = {"code": 100, "msg": "查询成功",
                  "results": [{"id": book.id, "name": book.name, "price": book.price} for book in obj]}
    # 因为JsonResponse只能发送字典的数据,我们要发的是一个列表,所以
    return JsonResponse(books_list, safe=False)
​

3.研究一下:QueryDict

from django.http import QueryDict
QueryDict的父亲是MultiValueDict,爷爷是dict,所以他是具备dict的所有功能,但是他也重写了一些方法
​
1.它能够处理一个键对应多个值的情况,这在HTML表单中很常见,例如多选框(<select multiple>)或具有相同名称的多个输入框
2.QueryDict:提供了一些特定的方法来处理表单数据和URL查询参数,如get()(获取单个值,如果键有多个值则获取最后一个值)、getlist()(获取键对应的所有值列表)等。
3.getlist()--》是他父类MultiValueDict的方法
用于获取与给定键相关联的所有值的列表
 def _getlist(self, key, default=None, force_list=False):
        """
        Return a list of values for the key.
​
        Used internally to manipulate values list. If force_list is True,
        return a new copy of values.
        """
        try:
            values = super().__getitem__(key)
        except KeyError:
            if default is None:
                return []
            return default
        else:
            if force_list:
                values = list(values) if values is not None else None
            return values

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值