回顾
基于django编写restful接口
APIView的流程分析
重写了dispatch方法:包装了request,执行了认证,权限,频率
原生request对象:
里面有个GET(以get形式提交的数据),以get形式提交的数据,都拆到environ内部,django把数据取出来转成了QueryDict的对象,而request.session不是原生request对象的属性,是在中间件中放进去的
drf的Request类:
data:post提交的数据,json格式,urlencoded,formdata编码方式的数据,data的类型并不是固定的,可能是QueryDict,也可能是字典
query_params:原生的GET
重写了__getattr__:对象.属性,当属性不存在就会执行该方法,return getattr(self._requset,'属性'),这样就能通过封装后的request.属性也能拿到值
序列化源码分析
many = True的时候,生成的是列表中放了一个个序列化对象
many = False的时候,生成的是一个序列化对象
new__控制的:返回什么样格式的就走什么样格式的__init,比如返回的是字符串格式的就会走字符串格式的__init__,即实例化的时候就产生一个字符串
校验源码部分:调用了bookser.is_valid方法才走校验,内部走了self.run_validation方法(要从根上找),在Serilaizer类中找到了run_validation方法
重点:self.to_internal_value(局部钩子)/self.validate(全局钩子),Serializer类中找到了to_internal_value,去对象内部反射validate_字段名的方法,如果不为None,直接执行,于是就执行了咱们自己写的局部校验的函数
序列化对象.data:执行Serializer内的data方法,又执行了父类(BaseSerializer)的data方法,执行self.to_representation(其实执行的是Serializer内的to_representation方法),最终执行的是每个字段对象的get_attribute方法,找字段对象的该方法,在Field中找到了该方法,执行了get_attribute(instance, self.source_attrs)
self.source_attrs:每个字段source后面指定的根据.切分后的列表(publish.name:就会被分成[publish,name]),如果是方法会执行方法,如果是字段,通过反射取出值
认证
使用(必会):
写一个认证类(继承BaseAuthentication)
重写authenticate方法,把request对象传入
能从request对象中取出用户携带的token,根据token判断是否登入,如果登入,返回两个值,user对象,token对象,如果没有登入就抛出异常raise AuthenticationFailed('您没有登录')
局部使用、全局使用、局部禁用
update_or_create()有就更新,没有就创建models.Token.objects.update_or_create(user=user,defaults={'token':token})
uuid的使用:生成一个唯一的随机字符串
源码分析:
APIVIew中的dispatch=>self.initial(认证,频率,权限)=>self.perform_authentication(认证)===>本质又调用了新的request对象的user方法
request.user内部执行了:self._authenticate(注意self是新的request对象),循环拿到一个个认证类的对象,执行对象的authenticate方法,传入request对象,一个个认证类的对象是在reuqest对象实例化的时候传入的,APIView中的get_authenticators,通过列表推导式生成一个个的认证类对象,然后传入request对象中
视图
基本写法:继承APIView
第二种写法
class PublishView(CreateModelMixin,ListModelMixin,GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializers
def post(self,request,*args, **kwargs):
return self.create(request, *args, **kwargs)
def get(self,request,*args, **kwargs):
return self.list(request, *args, **kwargs)
class PublishDetailView(RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin,GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializers
def get(self,request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self,request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self,request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
第三种写法
from rest_framework.generics import CreateAPIView,ListCreateAPIView,DestroyAPIView,RetrieveUpdateDestroyAPIView
class PublishView(ListCreateAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializers
class PublishDetailView(RetrieveUpdateDestroyAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializers
第四种写法
from django.views import View
from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
queryset=models.Publish.objects.all()
serializer_class=PublishSerializers
ViewSetMixin重写了as_view方法,路由配置就改了,可以写成映射的形式{get:get_one}
as_view方法内部执行效果
通过反射的取值跟赋值,完成映射,根据请求方式执行对应的方法(比如:get请求执行get_one方法,在路由中配置{get:getone})
补充:
1.基于对象的跨表查询和基于双下划线的查询区别是什么?
基于对象的跨表查询是子查询,基于双下划线是联表查询
2.left join/inner join/right join 区别是什么?
left join:基于左边的表连接(左表表字段齐全)
right join:基于右边的表连接(右表表字段齐全)
inner join:两张表有对应关系的连接