drff知识--04

2023-12-25 18:31:24

序列化回顾

#1 ?序列化类中的字段类:
? ? * 与model中得字段类几乎是一一对应的
? ? * 对应不上就用 CharField字符串
? ? *?DictField? ??ListField:
? ? ????????序列化时候,表模型中重写序列化的字段,方法返回值是字典或列表
? ????????? 反序列化时候,前端传入的是字典或列表
# 2 字段参数

* 私有的:
IntegerField:max_value,
CharField:
? ? allow_blank
? ? trim_whitespace
? ? max_length
? ? min_length
* 公共的:
read_only=False, ? ? 这个字段只做序列化
write_only=False, ? ?这个字段只做反序列化
----俩不能同时为True----你写的序列化类既要序列化,又要反序列化,字段可能不一样----
required=None,
default=empty,?
source=None,
error_messages=None,?
validators=None,?
allow_null=False

# 3 定制返回格式之source
? ?* 第一个用法:有时候我们向 序列化类写的字段跟表中不一样,使用source定制就能对应上
? ?* 第二个用法:表模型中写方法,可以通过source对应
? ?* 第三个用法:跨表(必须有关联关系)
# 4 定制返回格式(两种方法)
?? ?* 表模型中写方法,方法返回什么,序列化类中接收,ListField或DictField
? ? * 在序列化类中写:
? ? ?? ?????????SerializerMethodField
? ? ? ? ? ? ? ? 必须配合方法:get_字段名(self,对象)
# 5 ModelSerializer:继承了Serializer跟表可以关联上

class BookSerializer(ModelSerializer):
? ? id=serializer.CharField(default=20) #字段可以重写,优先用这个
? ? xx=serializer.SerializerMethodField(read_only=True)
? ? def get_xx():
? ? ? ? return 'xx'
? ? class Meta:
? ? ? ? model=表名
? ? ? ? # fields='__all__'
? ? ? ? fields=['id','name','price',即便是重写的字段,在这也要注册,既有序列化也有反序列化]
? ? ? ? depth
? ? ? ? extra_kwargs:给字段类上加属性的

# 之前学的全局钩子和局部钩子完全一致
? ?????????name=serializer.CharField(default=20)
? ?????????def validate_name
? ? ?后期可以不写create和update了,ModelSerializer帮咱们写了,有的情况需要重写

#?开源项目:?https://github.com/MicroPyramid/Django-CRM

装饰器例子

# 写个装饰器,装饰了视图函数(FBV),后续request.data,请求体中数据无论那种编码

from urllib import parse
def outer(func):
    def inner(request, *args, **kwargs):
        try:
            request.data = json.loads(request.body)     # json格式能load成功
        except Exception as e:
            request.data = request.POST
            if request.method == 'PUT':
                # key=value&key1=value2---》字典形式
                body_in = str(request.body, encoding='utf-8')  # 等同于  request.body.decode()
                body_in = parse.unquote(body_in)  # url 编码和解码
                request.data = {item.split('=')[0]: item.split('=')[1] for item in body_in.split('&')}
                # 笨办法
                # d = {}
                # sp_1 = body_in.split('&')
                # for item in sp_1:
                    # key, value = item.split("=")
                    # d[key] = value
                # request.data = d
        res = func(request, *args, **kwargs)
        return res
    return inner

from django.http import JsonResponse
@outer
def index(request):
    print(request.data)
    return JsonResponse({"code": 100})

## 咱们的装饰器,不能装cbv中得方法
class IndexView(APIView):
    def post(self,request):
        return Response('ok')

序列化例子

# 一次性提交作者和作者详情信息

views.py
from .serializer import AuthorSerializer
class AuthorView(APIView):
    def post(self, request):
        ser = AuthorSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '创建成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})

uurl.py
path('author/', views.AuthorView.as_view()),
serializer.py
# 这个序列化类用来---》反序列化
class AuthorSerializer(serializers.ModelSerializer):
    # 表中有的字段会映射过来,没有的字段,必须重写
    telephone = serializers.CharField()
    birthday = serializers.CharField()
    addr = serializers.CharField()

    class Meta:
        model = Author
        fields = ['name', 'age', 'telephone', 'birthday', 'addr']  # 前端提交过来的字段

    # 必须重写create
    def create(self, validated_data):
        telephone = validated_data.pop('telephone')
        birthday = validated_data.pop('birthday')
        addr = validated_data.pop('addr')
        # 先创建作者详情
        author_detail = AuthorDetail.objects.create(telephone=telephone, birthday=birthday, addr=addr)
        validated_data['author_detail'] = author_detail
        author = Author.objects.create(**validated_data)

        return author

模块与包回顾

# 脚本文件:? ? py文件能直接右键运行

? ?模块:一个py文件,被别的py文件导入

? ?包:一个文件夹下,有多个py文件,但是有个 __init__.py

#?如果包内,有些类,属性,函数想给外部用,放在包内部,导入起来又很深,我们就可以? ? ?在init中注册,以后只需要 ?from 包名 import init中注册的类,函数即可

# 导入模块或包使用的规则:?

? ? ?1、导入模块有相对导入绝对导入

????????????????相对导入是从当前py文件开始计算的

????????????????绝对的路径是从环境变量开始的

? ? ?2、脚本文件执行的路径,会自动加入环境变量

? ? ?3、以脚本运行的文件,不能使用相对导入,只能用绝对导入

? ? ?4、pycharm 会把项目根路径加入到环境变量,离开pycharm就不行了
? ? ?5、下载的第三方包,会放在site-package中,这个路径在环境变量中
? ? ? ? ?? ?第三方包导入自己的模块,它们用绝对多一些? ?from 它的包名 ?import xx
? ? ?? ?????????下载的第三方包,都在site-package中,而site-package一定在环境变量中

? ? ?6、自己写的包,推荐用相对,包内部,相对不会出错

反序列化校验源码分析(了解)

#1 ?执行 ser.is_valid() 就会执行反序列化的校验,从字段自己局部钩子再到全局钩子
#2 ?入口是:ser.is_valid()---》BaseSerializer 找到了
?? ?自己写的BookSerializer---》serializer.Serializer---->BaseSerializer?

def is_valid(self, *, raise_exception=False):
? ? ? ? # self 是 ser对象---》自己写的BookSerializer的对象--》一开始没有
? ? ? ? # 一旦有了,就不执行了,优化is_valid被多次调用,只会走一次校验
? ? ? ? if not hasattr(self, '_validated_data'):
? ? ? ? ? ? try:
? ? ? ? ? ? ? ? # 一旦执行过,以后self中就有_validated_data
? ? ? ? ? ? ? ? # 接下来看self.run_validation(self.initial_data)
? ? ? ? ? ? ? ? self._validated_data = self.run_validation(self.initial_data)
? ? ? ? ? ? except ValidationError as exc:
? ? ? ? ? ? ? ? self._validated_data = {}
? ? ? ? ? ? ? ? self._errors = exc.detail
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? self._errors = {}

? ? ? ? if self._errors and raise_exception:
? ? ? ? ? ? raise ValidationError(self.errors)

? ? ? ? return not bool(self._errors)

# 3 serializer.Serializer类的run_validation

def run_validation(self, data=empty):
? ? ? ? ? ? # data前端传入的--{"name":"张三","age":68}
? ? ? ? ? ? # value是---》前端传入的,字段自己校验通过的字典---{"name":"张三","age":68}
? ? ? ? ? ? value = self.to_internal_value(data) # 执行局部钩子
? ? ? ? ? ? try:
? ? ? ? ? ? ? ? self.run_validators(value) # 先不看,忽略掉
? ? ? ? ? ? ? ? # self 是 BookSerializer的对象,如果我们写了全局钩子,走我们自己的,如果没写,走父类的,父类的根本没做校验
? ? ? ? ? ? ? ? # value={"name":"张三","age":68}
? ? ? ? ? ? ? ? value = self.validate(value)# 执行全局钩子
? ? ? ? ? ? except (ValidationError, DjangoValidationError) as exc:
? ? ? ? ? ? ? ? raise ValidationError(detail=as_serializer_error(exc))

? ? ? ? ? ? return value

# 4全局钩子读完了:self 是 BookSerializer的对象
????????如果我们写了全局钩子,走我们自己的,如果没写,走父类的,父类的根本没做校验
# 5局部钩子:value = self.to_internal_value(data)--》Serializer类的
? ? ? ? for循环着去BookSerializer的对象中反射 validate_字段名的方法,有就执行

def to_internal_value(self, data):
? ? ? ? for field in fields: # 序列化类中所有字段类的对象 name=CharField()
? ? ? ? ? ? # self 是BookSerializer类的对象
? ? ? ? ? ? # 去BookSerializer类中,反射 ?validate_field字段类的对象.field_name
? ? ? ? ? ? validate_method = getattr(self, 'validate_' + field.field_name, None)
? ? ? ? ? ? try:
? ? ? ? ? ? ? ? # 如果能拿到,说明咱么写了局部钩子
? ? ? ? ? ? ? ? if validate_method is not None:
? ? ? ? ? ? ? ? ? ? # 执行局部钩子--》传入了当前字段的value值
? ? ? ? ? ? ? ? ? ? validated_value = validate_method(validated_value)
? ? ? ? ? ? except ValidationError as exc:
? ? ? ? ? ? ? ?# 如果抛异常,会被捕获
? ? ? ? ? ? ? ? errors[field.field_name] = exc.detail
? ? ? ? ? ? except DjangoValidationError as exc:
? ? ? ? ? ? ? ? errors[field.field_name] = get_error_detail(exc)
? ? ? ? ? ? except SkipField:
? ? ? ? ? ? ? ? pass
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? set_value(ret, field.source_attrs, validated_value)

? ? ? ? if errors:
? ? ? ? ? ? raise ValidationError(errors)

? ? ? ? return ret

# 保存,修改也好,都要用validated_data? ? ?
####读了局部和全局钩子的执行位置#####

断言

#?断言:符合条件,就继续走,不符合条件就会抛出 断言失败异常,异常信息就是字符串

# assert 后写条件,只要不符合条件,就会抛AssertionError异常,后面写异常信息

????????a = 10
????????assert a == 11, ("不等于11,报错了")

# 等同于上面只要一行代码,源码中喜欢用:
????????if not a == 11:
? ????????? raise Exception('不等于11,报错了')

# 源码中使用:
assert value is not None, '.validate() should return the validated data'

drf之请求

# Request 类的对象:
? ? ? ? ? ? ??from rest_framework.request import Request
? ?是新的request,用起来跟之前一样

? ?老的request在request._request
? ?request.data ?前端传入的请求体中得数据,无论那种编码

#?默认,视图类的方法,可以处理任意编码格式
?? ?????????urlencoded、form-data、json? ? ? ? ? ? ?

????????? ? 比如有的接口,只能接收json格式,其他格式都不能处理

# 配置方式一:视图类上配置

from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
# JSONParser:json
# FormParser:urlencoded
# MultiPartParser:form-data
class TestView(APIView):
    # parser_classes = [JSONParser]
    parser_classes = [JSONParser,FormParser]
    def post(self, request):
        print(request.data)
        return Response('ok')

# 配置方式二:settings.py ?配置文件中配置

setting.py
# 所有drf的配置,都要写在REST_FRAMEWORK 字典中
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': [
            # 'rest_framework.parsers.JSONParser',
            # 'rest_framework.parsers.FormParser',
            'rest_framework.parsers.MultiPartParser',
        ],
    }

views.py
class TestView(APIView):
        parser_classes = [JSONParser,FormParser]

# 全局使用某种,单某个视图类,局部使用:

????????优先用视图类配置的,视图类没配置--->项目配置文件,项目配置文件如果没配置--->drf配置文件(默认三个都支持)

# 一般只支持json
????????对于上传的文件的接口,单独配置只允许?form-data

drf之响应

from rest_framework.response import Response

data=None ?# 咱们给的字典或列表或字符串---》最终放到了http响应体中返回了
status=None #http响应状态码,默认是200,你可以改,改成from rest_framework import status 状态码 ? ?? ??? ? ? http响应状态码分别代表啥意思:200成功 ? 201 创建成功
template_name=None:用浏览器访问好看的页面--》指定的--》默认使用drf提供的--》后期可以自己写页面,使用?
headers=None, #响应头
content_type=None # 响应编码格式

# 配置方式跟请求解析类似:

# 方式一:在视图类上配置

class TestView(APIView):
? ? renderer_classes = [JSONRenderer,BrowsableAPIRenderer]

# 方式二:配置文件中配置

REST_FRAMEWORK = {
? ? 'DEFAULT_RENDERER_CLASSES': [
? ? ? ? 'rest_framework.renderers.JSONRenderer',
? ? ? ? 'rest_framework.renderers.BrowsableAPIRenderer',
? ? ],

}

今日思维导图:

文章来源:https://blog.csdn.net/qq_48064830/article/details/135156313
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。