一、版本控制组件
1、为什么要使用版本控制
首先我们开发项目是有多个版本的
当我们项目越来越更新,版本就越来越多,我们不可能新的版本出了,以前旧的版本就不进行维护了
像bootstrap有2、3、4版本的,每个版本都有它对应的url,https://v2.bootcss.com/ 、 https://v3.bootcss.com/
这就需要我们对版本进行控制,这个DRF也给我们提供了一些封装好的版本控制方法
2、原理
1.
在DRF框架中,它默认帮我们设置了版本信息在request.version和request.versioning_scheme中,
只是DRF默认的版本信息是None,我们需要重写一些配置,让request.version携带上我自定义的版本信息
request.versioning_scheme是实现版本控制的类的实例化对象
2.
CBV视图函数都是首先会去执行as_view方法的,as_view会找到路由的分发方法dispatch,在真正分发之前会执行initial方法
3、使用
0. 在哪里取版本信息 我们的版本类必须重写determine_version这个方法,request.version就是拿它的返回值 在视图中就可以使用request.version取到版本信息 1. 新建一个py文件 我建在utils文件夹下的version.py 在version.py下重写一个MyVersion类 注意:必须重写determine_version这个方法,因为request.version就是拿它的返回值 class MyVersion(object): def determine_version(self,request, *args, **kwargs): version = request.query_params.get("version", "v1") return version 2. 去项目的settings配置 # 覆盖DRF原本的配置DEFAULT_VERSIONING_CLASS,让它的值指向我们写的那个类 REST_FRAMEWORK = { ‘DEFAULT_VERSIONING_CLASS‘: ‘utils.version.MyVersion‘ } 3. 在视图中使用 class VersionView(APIView): def get(self, request): print(request.version) print(request.versioning_scheme) if request.version == ‘v1‘: return Response("v1版本") elif request.version == ‘v2‘: return Response(‘v2版本‘) return Response(‘不存在的版本‘)
4、DRF的versioning模块
1. 在这里模块内给我们配置了各种获取版本的类 2. versioning模块
# 基础类 class BaseVersioning(object): default_version = api_settings.DEFAULT_VERSION allowed_versions = api_settings.ALLOWED_VERSIONS version_param = api_settings.VERSION_PARAM def determine_version(self, request, *args, **kwargs): msg = ‘{cls}.determine_version() must be implemented.‘ raise NotImplementedError(msg.format( cls=self.__class__.__name__ )) def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): return _reverse(viewname, args, kwargs, request, format, **extra) def is_allowed_version(self, version): if not self.allowed_versions: return True return ((version is not None and version == self.default_version) or (version in self.allowed_versions)) # 在请求头中携带版本信息 class AcceptHeaderVersioning(BaseVersioning): """ GET /something/ HTTP/1.1 Host: example.com Accept: application/json; version=1.0 """ # 在URL中携带版本信息 class URLPathVersioning(BaseVersioning): ‘‘‘ urlpatterns = [ url(r‘^(?P<version>[v1|v2]+)/users/$‘, users_list, name=‘users-list‘), url(r‘^(?P<version>[v1|v2]+)/users/(?P<pk>[0-9]+)/$‘, users_detail, name=‘users-detail‘) ] ‘‘‘ # 在namespace中携带版本信息 class NamespaceVersioning(BaseVersioning): ‘‘‘ # users/urls.py urlpatterns = [ url(r‘^/users/$‘, users_list, name=‘users-list‘), url(r‘^/users/(?P<pk>[0-9]+)/$‘, users_detail, name=‘users-detail‘) ] # urls.py urlpatterns = [ url(r‘^v1/‘, include(‘users.urls‘, namespace=‘v1‘)), url(r‘^v2/‘, include(‘users.urls‘, namespace=‘v2‘)) ] ‘‘‘ # 在域名中携带版本信息 class HostNameVersioning(BaseVersioning): """ GET /something/ HTTP/1.1 Host: v1.example.com Accept: application/json """ # 在参数中携带版本信息 class QueryParameterVersioning(BaseVersioning): """ GET /something/?version=0.1 HTTP/1.1 Host: example.com Accept: application/json """
version模块的类
3. 基础类的三个配置 REST_FRAMEWORK = { ‘DEFAULT_VERSIONING_CLASS‘: ‘utils.version.MyVersion‘, # 默认版本 ‘default_version‘: ‘v1‘, # 可用版本 ‘allowed_versions‘: [‘v1‘, ‘v2‘], # 参数 ‘version_param‘: ‘version‘, }
4. 使用DRF的版本控制 方法一 1. 在utils文件夹下的version.py继承versioning的类 from rest_framework import versioning class MyVersion(versioning.URLPathVersioning): pass 2. urls.py urlpatterns = [ # url(r‘^version_demo/‘, views.VersionView.as_view()), url(r‘^(?P<version>[v1|v2]+)/version_demo/‘, views.VersionView.as_view()), ] 3. settings.py REST_FRAMEWORK = { ‘DEFAULT_VERSIONING_CLASS‘: ‘utils.version.MyVersion‘, # 默认版本 ‘default_version‘: ‘v1‘, # 可用版本 ‘allowed_versions‘: [‘v1‘, ‘v2‘], # 参数 ‘version_param‘: ‘version‘, } 4.在视图中使用需要接收参数version class VersionView(APIView): def get(self, request, version): print(request.version) print(request.versioning_scheme) if request.version == ‘v1‘: return Response("v1版本") elif request.version == ‘v2‘: return Response(‘v2版本‘) return Response(‘不存在的版本‘) 5. 在浏览器中 可以输入: v1/version_demo/ v2/version_demo/ 方法二 其他步骤基本一样,只是我们在配置的时候直接指定某个类 1. urls.py urlpatterns = [ # url(r‘^version_demo/‘, views.VersionView.as_view()), url(r‘^(?P<version>[v1|v2]+)/version_demo/‘, views.VersionView.as_view()), ] 2. settings.py REST_FRAMEWORK = { ‘DEFAULT_VERSIONING_CLASS‘: ‘rest_framework.versioning.URLPathVersioning‘, # 指定URLPathVersioning这个类 # 默认版本 ‘default_version‘: ‘v1‘, # 可用版本 ‘allowed_versions‘: [‘v1‘, ‘v2‘], # 参数 ‘version_param‘: ‘version‘, }
二、认证
1、为什么要认证
我们可以在网站上登录,然后可以有个人中心,对自己信息就行修改
但是我们每次给服务器发请求,由于Http的无状态,导致我们每次都是新的请求
那么服务端需要对每次来的请求进行认证,看用户是否登录,以及登录用户是谁
那么我们服务器对每个请求进行认证的时候,不可能在每个视图函数中都写认证
一定是把认证逻辑抽离出来,以前我们可能会加装饰器,或者中间件,DRF框架也有它的认证
2、原理
在前端进行登录的时候,用户名和密码输入正确后,后端根据用户名和密码拿到这个用户的一些信息(用户名,性别等),
把这些信息加密后生成一个随机字符串token返回给前端,
前端下次请求再来的时候,带上这个随机字符串,后端根据自己的解密算法再算出来,实现认证。
3、token认证
0. 在哪里取认证的信息 我们的认证类必须重写authenticate这个方法,返回值是元组 第一个值赋值给了request.user, 第二个赋值给request.auth 在视图中就可以使用request.user和request.auth取到认证的信息 1. models.py class User(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) # 用UUID字符串存随机字符串 token = models.UUIDField(null=True, blank=True) CHOICES = ((1, "vip"), (2, "普通用户"), (3, "vvip")) 2. settings配置 # 跟版本一样,覆盖原本的配置,使用自己的配置 REST_FRAMEWORK = { # 配置认证类 # 这样配是全局,所有路由都要认证 ‘DEFAULT_AUTHENTICATION_CLASSES‘:[‘utils.auth.MyAuth‘, ] } 3. utils/auth.py from rest_framework import authentication from AuthDemo.models import User from rest_framework.exceptions import AuthenticationFailed class MyAuth(authentication.BaseAuthentication): # 必须重写authenticate这个方法,返回值是元组 # 第一个值赋值给了request.user, 第二个赋值给request.auth def authenticate(self, request): # 获取前端携带的token,看token是否合法 token = request.query_params.get("token", "") if not token: raise AuthenticationFailed("没有携带token") user_obj = User.objects.filter(token=token).first() # 返回需要的信息 if user_obj: return (user_obj, token) # 验证不通过,抛出异常 raise AuthenticationFailed("token不合法") 4. 视图 class TestView(APIView): def get(self, request): print(request.user) print(request.auth) return Response("登陆后发送的数据") 5. 局部配置 1. 如果只是某些路由需要认证,那么可以局部设置认证,包括版本也可以局部认证 2. 把settings的配置注释掉 3. 在需要认证的视图中声明 from utils.auth import MyAuth class TestView(APIView): authentication_classes = [MyAuth, ] # 局部配置认证组件 # versioning_class = [] # 局部配置版本组件 def get(self, request): print(request.user) print(request.auth) return Response("登陆后发送的数据")
原文地址:https://www.cnblogs.com/Zzbj/p/10112019.html