【DRF框架之梅开二度】
DRF 框架
restful 规范
- 定义
- 软件的一种架构风格,通过HTTP协议进行数据交互。核心思想:将系统中的资源(网页,文本,数据等)表示为统一的资源标识符(URL)
- 使用:POST,GET,PUT,DELETE等HTTP请求方法,对资源操作
- 特点
- 使用HTTP方法表示资源操作类型。GET 获取,POST创建,PUT更新,DELETE删除
- 使用URL表示资源:URL尽可能多的反应资源的层次结构和名称
- 使用状态码操作:2xx,4xx,5xx等
- 使用JSON/XML作为数据传输格式。保证数据的可读性和可扩展性
- 无状态:restful系统是无状态的,每个请求是独立的,不依赖之前的请求和会话
- 缓存友好性:restful支持缓存,提高性能和减少服务资源负载
DRF 组件认证过程
1. 用户发送请求到 API端点(服务,服务器上的服务)
2. API检查请求头的Authorization字段,来确定请求是否经过认证
3. 如果请求未经过认证,则返回401,提示用户进行认证操作
4. 如果请求经过认证,则要求API检查请求的权限,确定用户是否具有执行该操作的权限
5. 如果用户执行该做操没有权限,则返回403,提示用户没有权限执行该操作
6. 如果用户具有该操作的权限,则执行API逻辑,并返回响应结果
7. 认证方式:基本认证,令牌认证,JSON WEB Token认证等
DRF 组件中的权限认证
- 视图级权限 ,视图中添加 permission_classes 属性指定权限
from rest_framework.permissions import IsAuthenticated
class MyView(APIView):
permission_classes = (IsAuthenticated,)
- 路由级权限,路由中添加 permission_classes 属性指定权限
from rest_framework.permissions import IsAuthenticated
router = DefaultRouter()
router.register(r'users', UserViewSet, base_name='user')
router.route('list', permission_classes=(IsAuthenticated,))
- 自定义权限。
from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
def has_permission(self, request, view):
# 自定义权限逻辑
return True
class MyView(APIView):
permission_classes = (MyPermission,)
DRF 组件中的节流实现方式
- 频率限制
- 用户在一定时间可以发送的请求数量。如:限制用户每分钟只能发送10个请求。
- 实现:通过cache模块,DRF提供 _throttled_cache 中间件,来实现频率限制
- 代码如下:
from django.core.cache import cache
from django.middleware.cache import ThrottledCache
# 创建一个 ThrottledCache 实例
throttled_cache = ThrottledCache(timeout=60, key_prefix='my_cache')
# 将 ThrottledCache 实例添加到 DRF 的中间件列表中
MIDDLEWARE = [
xxxxx,
xxxxx,
'throttled_cache.middleware.ThrottledCacheMiddleware',
]
- 请求限制
- 指某个IP在一定时间内发送的请求数量。如:限制43.10.10.22 ip 每小时只能发送1000个请求
- 实现:使用django的request模块,DRF 提供 _throttled_request 中间件来限制
- 代码:
# 在视图中使用 ThrottledCache 中间件
from rest_framework.response import JsonResponse
def my_view(request):
# 检查请求是否被缓存
if not throttled_cache.get_cache_key(request):
return JsonResponse({'error': '请求太频繁,请稍后再试。'}, status=429)
# 处理请求
#...
# 缓存请求
throttled_cache.set_cache_key(request)
# 返回响应
return JsonResponse({'result': '请求处理成功。'})
什么是JWT?
-
一般用于前后端分离项目。 用于做用户认证
-
jwt实现原理
- 用户登陆成功后,返回一段字符串(token)
- token 是由 三段组成
- 第一段: 类型 和 算法 信息
- 第二段: 用户信息 + 超时时间
- 第三段: hs256加密 (拼接前两段信息)
- 在使用 base64url 进行二次加密。(处理&和特殊字符)
- 后端验证token
- token 超时验证
- token的合法性验证
-
jwt的优势
- 服务端不保存token信息,只在客户浏览器保存。 后端只负责校验
- 内部集成超时时间,后端可以根据时间校验token是否超时
- 用户不可修改token,修改后token验证失败
Django 编写试图方式
- 第一种:APIView
- 自己编写CRUD视图,编写分页等
- 第二种:ListAPIView,CreateAPIView等
- 实现认证,分页,CRUD等
- 第三种:GenericViewSet,ListModelMixin,CreateModelMixin等
- 集成所有的功能,需要在路由指定方法
- 第四种 viewsetes.ModelViewSet 实现上面所有功能
DRF 回顾
- 装饰器
def wrapper(func):
def inner(*args,**kwargs):
ret = func(*args,**kwargs)
return ret
return inner
# 装饰器1
@wrapper
def index(f1):
pass
# 装饰器2
index = wrapper(index)
-
django csrf_exempt 免认证
from django.views.decorators.csrf import csrf_exempt from django.shortcuts import HttpResponse @csrf_exempt def index(request): return HttpResponse('...') # index = csrf_exempt(index) urlpatterns = [ url(r'^index/$',index), ]
urlpatterns = [ url(r'^login/$',account.LoginView.as_view()), ] class APIView(View): @classmethod def as_view(cls, **initkwargs): view = super().as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. return csrf_exempt(view)
-
面向对象中 基于 异常+继承 实现约束
class BaseVersioning: def determine_version(self, request, *args, **kwargs): raise NotImplementedError("must be implemented") class URLPathVersioning(BaseVersioning): def determine_version(self, request, *args, **kwargs): version = kwargs.get(self.version_param, self.default_version) if version is None: version = self.default_version if not self.is_allowed_version(version): raise exceptions.NotFound(self.invalid_version_message) return version
-
面向对象的封装
class Foo(object): def __init__(self,name,age): self.name = name self.age = age obj = Foo('汪洋',18)
class APIView(View): def dispatch(self, request, *args, **kwargs): self.args = args self.kwargs = kwargs request = self.initialize_request(request, *args, **kwargs) self.request = request ... def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, parsers=self.get_parsers(), authenticators=self.get_authenticators(), # [MyAuthentication(),] negotiator=self.get_content_negotiator(), parser_context=parser_context )
-
面向对象的继承
class View(object): pass class APIView(View): def dispatch(self): method = getattr(self,'get') method() class GenericAPIView(APIView): serilizer_class = None def get_seriliser_class(self): return self.serilizer_class class ListModelMixin(object): def get(self): ser_class = self.get_seriliser_class() print(ser_class) class ListAPIView(ListModelMixin,GenericAPIView): pass class UserInfoView(ListAPIView): pass view = UserInfoView() view.dispatch()
class View(object): pass class APIView(View): def dispatch(self): method = getattr(self,'get') method() class GenericAPIView(APIView): serilizer_class = None def get_seriliser_class(self): return self.serilizer_class class ListModelMixin(object): def get(self): ser_class = self.get_seriliser_class() print(ser_class) class ListAPIView(ListModelMixin,GenericAPIView): pass class UserInfoView(ListAPIView): serilizer_class = "汪洋" view = UserInfoView() view.dispatch()
class View(object): pass class APIView(View): def dispatch(self): method = getattr(self,'get') method() class GenericAPIView(APIView): serilizer_class = None def get_seriliser_class(self): return self.serilizer_class class ListModelMixin(object): def get(self): ser_class = self.get_seriliser_class() print(ser_class) class ListAPIView(ListModelMixin,GenericAPIView): pass class UserInfoView(ListAPIView): def get_seriliser_class(self): return "咩咩" view = UserInfoView() view.dispatch()
-
反射
class View(object): def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. 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 return handler(request, *args, **kwargs)
-
发送ajax请求
$.ajax({ url:"地址", type:"GET", data:{}, success:function(e){ console.log(e) } })
-
浏览器具有 同源策略 跨域如何产生的? 导致 ajax请求+跨域 存在 无法获取数据
- 简单请求,发送一次请求
- 复杂请求,先做 options 请求预检,在发送真正的请求
IP 端口 协议
-
如何解决 跨域
CORS 本质:设置响应头
-
常见的HTTP请求方法
Get,POST,PUT,OPTIONS,PATCH,DELETE ...
-
HTTP 请求头。Content-Type 请求头
- application/x-www-form-urlencoded django 的 request.POST 和 request.body 中均有数据 - appliction/json django 的 request.POST 没有值,request.body 有数据
-
django 的 fbv 和 cbv 都能遵循 restful 规范接口
-
django rest framework 框架 实现 restful api 开发
- 免除 csrf 认证 - 分页 - 权限 - 视图(APIView,ListApiView,ListModelMixin...) 类的继承 - 序列化 serializer - 版本 Version - 节流 - 解析器 - 筛选器 - 认证 - 渲染器
-
简述 drf 中的认证流程
-
简述drf 中的节流实现原理, 匿名用户 和 非匿名用户 实现频率限制
-
GenericAPIView 视图类
- 提供了一些规则 - serilizer_class = None - lookup_field = 'pk' - queryset = None - filter_backends = - get_queryset(self) - get_object(self) - get_serializer_class(self): return self.
-
jwt的优势
-
序列化时,many=True 和 many = False 的区别
-
django 的 F 查询
-
django 的 获取空的queryset
models.XXX.objects.all().none()
-
应用 DRF 中的功能开发
***** 非常重要 视图: 序列化: 解析器 request.data / request.query_params 渲染器:Response **** request 对象封装 版本处理 分页处理 *** 认证 权限 节流 - 基于 APIView 实现 呼啦圈 项目 - 基于 GenericView,ListModelMixin 实现呼啦圈 项目
-
GenericAPIView视图类的作用?
他提供了一些规则,例如: class GenericAPIView(APIView): serializer_class = None queryset = None lookup_field = 'pk' filter_backends = api_settings.DEFAULT_FILTER_BACKENDS pagination_class = api_settings.DEFAULT_PAGINATION_CLASS def get_queryset(self): return self.queryset def get_serializer_class(self): return self.serializer_class def filter_queryset(self, queryset): for backend in list(self.filter_backends): queryset = backend().filter_queryset(self.request, queryset, self) return queryset @property def paginator(self): if not hasattr(self, '_paginator'): if self.pagination_class is None: self._paginator = None else: self._paginator = self.pagination_class() return self._paginator 他相当于提供了一些规则,建议子类中使用固定的方式获取数据,例如: class ArticleView(GenericAPIView): queryset = models.User.objects.all() def get(self,request,*args,**kwargs): query = self.get_queryset() 我们可以自己继承GenericAPIView来实现具体操作,但是一般不会,因为更加麻烦。 而GenericAPIView主要是提供给drf内部的 ListAPIView、Create.... class ListModelMixin: def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) class ListAPIView(mixins.ListModelMixin,GenericAPIView): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) class MyView(ListAPIView): queryset = xxxx ser...
总结:GenericAPIView主要为drf内部帮助我们提供增删改查的类LIstAPIView、CreateAPIView、UpdateAPIView、提供了执行流程和功能,我们在使用drf内置类做CURD时,就可以通过自定义 静态字段(类变量)或重写方法(get_queryset、get_serializer_class)来进行更高级的定制。
-
序列化时many=True和many=False的区别?
在 Django Rest Framework(DRF)中,序列化时 many=True 和 many=False 的区别在于它们指定了序列化的对象是单个实例还是一个集合。 many=True 表示序列化的是一个集合(列表、可迭代对象等)。这意味着序列化器将处理多个对象,并返回一个包含多个序列化实例的数组或列表。 many=False 表示序列化的是单个实例。序列化器将处理单个对象,并返回该单个序列化实例。 以下是一些主要的区别: 返回格式:many=True 返回列表,many=False 返回单个对象。 数据处理:在序列化多个对象时,many=True 会逐个处理每个对象。 视图响应:根据 many 的设置,视图可能会返回不同的 HTTP 状态码和响应结构。 序列化逻辑:可能会有不同的逻辑来处理单个实例或集合。 通过设置 many 参数,DRF 可以灵活地处理单个对象和对象集合的序列化需求,以便与客户端进行有效的数据交互。