源码分析: # 1 在路由中:path('books/', views.BookView.as_view()),请求来了 # 2 先看 as_view()---->APIView的 as_view---》as_view执行结果跟之前一样,去除了csrf认证 ? ? @classmethod ? ? def as_view(cls, **initkwargs): ? ? ? ? view = super().as_view(**initkwargs) # 调用父类的 as_view,view还是View的as_view ? ? ? ? # 以后所有请求,都不会做csrf认证了 ? ? ? ? return csrf_exempt(view) ? ?? # 3 请求来了执行 views.BookView.as_view()(request)--->view(request)--->csrf_exempt(view)(request)--->内部核心---》return self.dispatch(request) # 4 self 是 APIView类的对象---》APIView没有dispatch---》APIView的dispatch,核心代码如下 ? ? def dispatch(self, request, *args, **kwargs): ? ? ? ? # 后续的request都是 initialize_request 返回结果--》新的request--》drf的Requet类的对象 ? ? ? ? request = self.initialize_request(request, *args, **kwargs) ? ? ? ? # 新的request放到了 self.request中---》self是BookView类的对象 ? ? ? ? # 后续视图类的方法中 可以直接 self.request取出 当次请求的request对象 ? ? ? ? self.request = request ? ? ? ? try: ? ? ? ? ? ? # 执行了三大认证: ? ? ? ? ? ? ''' ? ? ? ? ? ? self.perform_authentication(request) ? ? ? ? ? ? self.check_permissions(request) ? ? ? ? ? ? self.check_throttles(request) ? ? ? ? ? ? ''' ? ? ? ? ? ? self.initial(request, *args, **kwargs) ? ? ? ? ? ? ###### 通过反射,去视图类中:BookView中执行跟请求方式同名的方法 ? ? ? ? ? ? if request.method.lower() in self.http_method_names: ? ? ? ? ? ? ? ? handler = getattr(self, request.method.lower(), ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? self.http_method_not_allowed) ? ? ? ? ? ? else: ? ? ? ? ? ? ? ? handler = self.http_method_not_allowed ?? ??? ? ? # request是新的Request类的对象了 ?get方法的第一个参数request也是新的 ? ? ? ? ? ? response = handler(request, *args, **kwargs) ?? ? ? ? ? ########################执行视图类的方法结束###### ? ? ? ? except Exception as exc: ? ? ? ? ? ? # 如果在执行三大认证或视图类方法中,出了错,都会被异常捕获,统一处理 ? ? ? ? ? ? response = self.handle_exception(exc) ? ? ? ? self.response = self.finalize_response(request, response, *args, **kwargs) ? ? ? ? return self.response ? ?? # 5 看self.initialize_request 是APIView的 ? ? def initialize_request(self, request, *args, **kwargs): ? ? ? ? # 类实例化得到对象,传入一些参数 ? ? ? ? # Request类--》drf提供的类 ? ? ? ? from rest_framework.request import Request ? ? ? ? return Request( ? ? ? ? ? ? request, ? ? ? ? ? ? parsers=self.get_parsers(), ? ? ? ? ? ? authenticators=self.get_authenticators(), ? ? ? ? ? ? negotiator=self.get_content_negotiator(), ? ? ? ? ? ? parser_context=parser_context)
# 总结:
?? ?1 以后视图类方法中得request对象,变成了新的request,它是rest_framework.request.Request 的对象了,但是用起来跟之前一样
? ? 2 把新的request对象,同时放到了 视图类的对象中 ?self.request = request ?后续从视图类中可以直接通过 self.request取出来
? ? 3 在执行视图类的方法之前,执行了三大认证
? ? 4 如果三大认证或视图类的方法执行出错,会有全局异常处理
? ? 5 以后所有的接口都去除了csrf认证
# 分析APIVIew时,分析出,以后request都是新的request了
????????是drf提供的Request的对象? ?from rest_framework.request import Request
# 源码解析之 __init__--->老的request在新的内部---》request._request: # 先看 __init__--->类实例化得到对象时,对对象进行初始化,往对象中放数据 ? ? def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None): ? ? ? ? # 传入的request是老的,django原生的request ? ? ? ? # 放到了self._request,self 是新的request类的对象 ? ? ? ? self._request = request ? ? ? ? self._data = Empty ? ? ? ? self._files = Empty? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?request = self.initialize_request(request, *args, **kwargs) # 前面是新的,后面是老的 ? ? ? ? return Request(request) # 老的
# 以后用新的跟用老的一样, 是因为新的request包含了老的,并且还有自己的新功能
# 魔法方法:在类内部,以 __开头 ?__结尾的方法, 在某种情况下会自动调用,他们称之为魔法方法
? ? ????????__init__:? 在调用类名()会自动触发
? ? ? ? ? ? __str__: ? print对象时自动触发??
? ? ??还有很多,所有类都继承object类,它都在object类中
? #? __getattr__ :通过对象.属性 ,属性不存在时会触发
def __getattr__(self, attr): ? ? try: ? ? # 通过反射,去老的中取,能取到就返回,取不到,执行except代码,再取不到就报错 ? ? ? ? return getattr(self._request, attr) ? ? except AttributeError: ? ? ? ? return self.__getattribute__(attr)
# APIView中的request :
? ? 1 新的request中有老的requet, 在request._request
? ? 2 新的request 多了data属性,客户端提交的请求体中得数据????????????????无论以那种方式编码,都在request.data中
? ? 3 其他的使用,跟之前老request一模一样request.method request.path request.POST request.GET request.FILES 。。。
# 总结:
1 原生django的post方法处理提交数据,只能处理urlencoded和form-data编码????????????????从request.POST中取
2 原生djagno的put处理不了提交的数据,需要我们自己从body中取出来处理
? ? ?? ?-分不同编码格式:
? ? ? ? ?? ?urlencoded:name=lqz&age=19? ? ?# 用字符串切割
? ? ? ? ? ? json:{"xxz":"xx","yyz":"yyy"}? ? ? ? ? ?# 要用json.loads? 进行反序列化? ? ? ? ??
3 原生django不能处理json提交的数据,需要自己做(put,post)
4 新的request解决了所有问题? ? ?#?request.data? ?
# 序列化类可以干的事:
? ? ????????序列化qs对象,单个对象,做序列化给前端
? ? ????????前端传入数据,校验数据是否合法
? ?????????反序列化,前端传入数据,存到数据库中# 继承APIView+Response实现 Publish的5个接口:
class PublishView(APIView): def get(self, request): publish_list = Publish.objects.all() l = [] for publish in publish_list: l.append({'name': publish.name, 'addr': publish.addr}) return Response({'code': 100, 'msg': '查询所有成功', 'results': l}) def post(self, request): # 如果是urlencoded编码,这种方式不行 publish = Publish.objects.create(**request.data) publish = Publish.objects.create(name=request.data.get('name'), addr=request.data.get('addr')) return Response({'code': 100, 'msg': '新增成功', 'results': {'name': publish.name, 'addr': publish.addr}})
class PublishDetailView(APIView): def get(self, request, pk): publish = Publish.objects.filter(pk=pk).first() return Response( {'code': 100, 'msg': '查询单条成功', 'results': {'name': publish.name, 'addr': publish.addr}}) def put(self, request, pk): publish = Publish.objects.filter(pk=pk).first() publish.name = request.data.get('name') publish.addr = request.data.get('addr') publish.save() return Response({'code': 100, 'msg': '修改成功', 'result': {'name': publish.name, 'addr': publish.addr}}) def delete(self, request, pk): Publish.objects.filter(pk=pk).delete() return Response({'code': 100, 'msg': '删除成功'})
# ?drf 提供的序列化器,实现序列化,反序列化和数据校验?
# 使用步骤:
1、写个py文件,叫serializer.py
?2、写个类,继承serializers.Serializer
3、在类中写要序列化的字段:class PublishSerializer(serializers.Serializer): ? ? ?name = serializers.CharField() # 写字段,要序列化的字段 ? ? ?addr = serializers.CharField() ? ? ?id = serializers.IntegerField()
4、在视图类中使用,完成 ?序列化:
多条: ser = PublishSerializer(instance=publish_list, many=True) ??? ? ser.data ?序列化后的数据 单条: ser = PublishSerializer(instance=publish) ??? ? ser.data ?序列化后的数据
# 视图类: from .serializer import PublishSerializer class PublishView(APIView): def get(self, request): publish_list = Publish.objects.all() ser = PublishSerializer(instance=publish_list, many=True) # 如果序列化多条,要many=True return Response({'code': 100, 'msg': '查询所有成功', 'results': ser.data}) class PublishDetailView(APIView): def get(self, request, pk): publish = Publish.objects.filter(pk=pk).first() ser = PublishSerializer(instance=publish) # 单个不写many=True return Response( {'code': 100, 'msg': '查询单条成功', 'results': ser.data})
# 序列化类: from rest_framework import serializers class PublishSerializer(serializers.Serializer): # 写字段,要序列化的字段 name = serializers.CharField() # addr = serializers.CharField() id = serializers.IntegerField()
# 路由 urlpatterns = [ path('publish/', views.PublishView.as_view()), path('publish/<int:pk>', views.PublishDetailView.as_view()), ]
# 序列化类中可以做字段校验, 三层
?第一层:字段自己的serializers.CharField(max_length=12,min_length=3)
?第二层:局部钩子def validate_name(self, name): ? ? ?if name.startswith("sb"): ? ? ? # 抛异常 ? ? ? ? ?raise ValidationError('不能以sb开头') ? ? ?return name def validate_addr(self, addr): ? ? ?if 'sb' in addr: ? ? ? # 抛异常 ? ? ? ? ?raise ValidationError('地址中不能有sb') ? ? ?return addr
第三层:全局钩子(注意:前端多传的,这里不会有)?
def validate(self, attrs): print(attrs) ? ? # 多个字段同时校验 ? ? # 出版社名和地址不能一样---》出版社前3个字不能和地址前3个字一样 ? ? if attrs.get('name')[:3] == attrs.get('addr')[:3]: ? ? ? ? ?raise ValidationError('出版社名和地址不能一样') ? ? return attrs
# 视图类中:
from .serializer import PublishSerializer Class PublishView(APIView): def get(self,request): publish_list = Publish.objects.all() ser = PublishSerializer(instance=publish_list, many=True) # 如果序列化多条,要many=True return Response({'code': 100, 'msg': '查询所有成功', 'results': ser.data}) def post(self,request): ser = PublishSerializer(data=request.data) ?# 把待校验数据传入 if ser.is_valid(): ? # 做数据校验---》三层 ? ? ? ? ? ? print(ser.data) ? ? ? ? else: ? ? ? ? ? ? print(ser.errors) ?# 没有校验通过,打印错误信息
# 保存:
1、在序列化类中,保存必须重写 create,完成真正的保存
def create(self, validated_data): ? ? ?# validated_data 校验过后的数据---》多传的数据,在这没有 ? ? ?publish = Publish.objects.create(**validated_data) ? ? ?return publish ?# 不要忘了返回新增的对象---》后续会拿着这个对象做序列化 ?ser.data--->根据它做序列化的
2、在视图类中,数据校验通过后,调用ser.save()
? ?? ??
# 修改功能,也要校验和保存1 在序列化类中,必须重写 update,完成真正的修改 def update(self, instance, validated_data): ?# {name:上海出版社,add:上海地址} ? ? ?instance.name=validated_data.get('name') ? ? ?instance.addr=validated_data.get('addr') ? ? ?instance.save() # publish 对象的save---》保存到数据中 ? ? ?return instance 2 视图类中 ser = PublishSerializer(instance=publish, data=request.data) ser.save() # 虽然新增或修改都是调用save,但是内部做了判断