#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帮咱们写了,有的情况需要重写
# 写个装饰器,装饰了视图函数(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'
# 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
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', ? ? ], }