DRF的版本、認證、權限

DRF的版本

版本控制是作什麼用的, 咱們爲何要用

首先咱們要知道咱們的版本是幹嗎用的呢~~你們都知道咱們開發項目是有多個版本的~~前端

當咱們項目愈來愈更新~版本就愈來愈多~~咱們不可能新的版本出了~之前舊的版本就不進行維護了~~~python

那咱們就須要對版本進行控制~~這個DRF也給咱們提供了一些封裝好的版本控制方法~~web

版本控制怎麼用

以前咱們學視圖的時候知道APIView,也知道APIView返回View中的view函數,而後調用的dispatch方法~django

執行self.initial方法以前是各類賦值,包括request的從新封裝賦值,下面是路由的分發,那咱們看下這個方法都作了什麼~~json

咱們能夠看到,咱們的version版本信息賦值給了 request.version  版本控制方案賦值給了 request.versioning_scheme~~api

只是DRF默認的版本信息是None,咱們須要重寫一些配置,讓request.version攜帶上我自定義的版本信息
request.versioning_scheme是實現版本控制的類的實例化對象~app

詳細用法

a. 基於url的get傳參方式框架

如:/users?version=v1ide

REST_FRAMEWORK = {
    'DEFAULT_VERSION': 'v1',            # 默認版本
    'ALLOWED_VERSIONS': ['v1', 'v2'],   # 容許的版本
    'VERSION_PARAM': 'version'          # URL中獲取值的key
}
settings.py
from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r'^test/', TestView.as_view(),name='test'),
]
urls.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import QueryParameterVersioning


class TestView(APIView):
    versioning_class = QueryParameterVersioning

    def get(self, request, *args, **kwargs):

        # 獲取版本
        print(request.version)
        # 獲取版本管理的類
        print(request.versioning_scheme)

        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse('test', request=request)
        print(reverse_url)

        return Response('GET請求,響應內容')

    def post(self, request, *args, **kwargs):
        return Response('POST請求,響應內容')

    def put(self, request, *args, **kwargs):
        return Response('PUT請求,響應內容')

views.py
views.py

b. 基於url的正則方式函數

如:/v1/users/

REST_FRAMEWORK = {
    'DEFAULT_VERSION': 'v1',            # 默認版本
    'ALLOWED_VERSIONS': ['v1', 'v2'],   # 容許的版本
    'VERSION_PARAM': 'version'          # URL中獲取值的key
}
settings.py
from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
]

urls.py
urls.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import URLPathVersioning


class TestView(APIView):
    versioning_class = URLPathVersioning

    def get(self, request, *args, **kwargs):
        # 獲取版本
        print(request.version)
        # 獲取版本管理的類
        print(request.versioning_scheme)

        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse('test', request=request)
        print(reverse_url)

        return Response('GET請求,響應內容')

    def post(self, request, *args, **kwargs):
        return Response('POST請求,響應內容')

    def put(self, request, *args, **kwargs):
        return Response('PUT請求,響應內容')

views.py
views.py

c. 基於 accept 請求頭方式

如:Accept: application/json; version=1.0

REST_FRAMEWORK = {
    'DEFAULT_VERSION': 'v1',            # 默認版本
    'ALLOWED_VERSIONS': ['v1', 'v2'],   # 容許的版本
    'VERSION_PARAM': 'version'          # URL中獲取值的key
}
settings.py
from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r'^test/', TestView.as_view(), name='test'),
]
urls.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import AcceptHeaderVersioning


class TestView(APIView):
    versioning_class = AcceptHeaderVersioning

    def get(self, request, *args, **kwargs):
        # 獲取版本 HTTP_ACCEPT頭
        print(request.version)
        # 獲取版本管理的類
        print(request.versioning_scheme)
        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse('test', request=request)
        print(reverse_url)

        return Response('GET請求,響應內容')

    def post(self, request, *args, **kwargs):
        return Response('POST請求,響應內容')

    def put(self, request, *args, **kwargs):
        return Response('PUT請求,響應內容')
views.py

d. 基於主機名方法

如:v1.example.com

ALLOWED_HOSTS = ['*']
REST_FRAMEWORK = {
    'DEFAULT_VERSION': 'v1',  # 默認版本
    'ALLOWED_VERSIONS': ['v1', 'v2'],  # 容許的版本
    'VERSION_PARAM': 'version'  # URL中獲取值的key
}
settings.py
from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r'^test/', TestView.as_view(), name='test'),
]
urls.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import HostNameVersioning


class TestView(APIView):
    versioning_class = HostNameVersioning

    def get(self, request, *args, **kwargs):
        # 獲取版本
        print(request.version)
        # 獲取版本管理的類
        print(request.versioning_scheme)
        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse('test', request=request)
        print(reverse_url)

        return Response('GET請求,響應內容')

    def post(self, request, *args, **kwargs):
        return Response('POST請求,響應內容')

    def put(self, request, *args, **kwargs):
        return Response('PUT請求,響應內容')
views.py

e. 基於django路由系統的namespace

如:example.com/v1/users/

REST_FRAMEWORK = {
    'DEFAULT_VERSION': 'v1',  # 默認版本
    'ALLOWED_VERSIONS': ['v1', 'v2'],  # 容許的版本
    'VERSION_PARAM': 'version'  # URL中獲取值的key
}
settings.py
from django.conf.urls import url, include
from web.views import TestView

urlpatterns = [
    url(r'^v1/', ([
                      url(r'test/', TestView.as_view(), name='test'),
                  ], None, 'v1')),
    url(r'^v2/', ([
                      url(r'test/', TestView.as_view(), name='test'),
                  ], None, 'v2')),

]
urls.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import NamespaceVersioning


class TestView(APIView):
    versioning_class = NamespaceVersioning

    def get(self, request, *args, **kwargs):
        # 獲取版本
        print(request.version)
        # 獲取版本管理的類
        print(request.versioning_scheme)
        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse('test', request=request)
        print(reverse_url)

        return Response('GET請求,響應內容')

    def post(self, request, *args, **kwargs):
        return Response('POST請求,響應內容')

    def put(self, request, *args, **kwargs):
        return Response('PUT請求,響應內容')
views.py

f. 全局使用

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
    'DEFAULT_VERSION': 'v1',
    'ALLOWED_VERSIONS': ['v1', 'v2'],
    'VERSION_PARAM': 'version' 
}
settings.py

DRF的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
    """
versioning模塊

 

DRF的認證

上面講版本的時候咱們知道~在dispatch方法裏~執行了initial方法~~那裏初始化了咱們的版本~~

若是咱們細心咱們能看到~版本的下面其實就是咱們的認證,權限,頻率組件了~~

咱們先看看咱們的認證組件~~

咱們進去咱們的認證看下~~

咱們這個權限組件返回的是request.user,那咱們這裏的request是新的仍是舊的呢~~

咱們的initial是在咱們request從新賦值以後的~因此這裏的request是新的~也就是Request類實例對象~~

那這個user必定是一個靜態方法~咱們進去看看~~

 

 

 

很明顯,有傳參

 

咱們經過上面基本能夠知道咱們的認證類必定要實現的方法~~以及返回值類型~~以及配置的參數authentication_classes~

DRF的權限 

權限是什麼

你們以前都應該聽過權限~那麼咱們權限究竟是作什麼用的呢~~

你們都有博客~或者去一些論壇~必定知道管理員這個角色~

好比咱們申請博客的時候~必定要向管理員申請~也就是說管理員會有一些特殊的權利~是咱們沒有的~~

這些對某件事情決策的範圍和程度~咱們叫作權限~~權限是咱們在項目開發中很是經常使用到的~~

那咱們看DRF框架給咱們提供的權限組件都有哪些方法~~

權限組件源碼

咱們以前說過了DRF的版本和認證~也知道了權限和頻率跟版本認證都是在initial方法裏初始化的~~

其實咱們版本,認證,權限,頻率控制走的源碼流程大體相同~~你們也能夠在源碼裏看到~~

咱們的權限類必定要有has_permission方法~不然就會拋出異常~~這也是框架給我提供的鉤子~~

咱們先看到在rest_framework.permissions這個文件中~存放了框架給咱們提供的全部權限的方法~~

我這裏就不帶着你們詳細去看每個了~你們能夠去瀏覽一下每一個權限類~看看每一個都是幹嗎的~~

這裏主要說下BasePermission 這個是咱們寫權限類繼承的一個基礎權限類~~~ 

認證權限的詳細用法

 用戶url傳入的token認證

from django.db import models

# Create your models here.


class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    token = models.UUIDField(null=True, blank=True)#隨機字符串
    CHOICES = ((1, "vip"), (2, "普通用戶"), (3, "vvip"))
    type = models.IntegerField(choices=CHOICES, default=2)
DRFDemo/AuthDemo/models.py

執行:makemigrations AuthDemo
migrate AuthDemo

from django.conf.urls import url, include
from django.contrib import admin



urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^book/', include("SerDemo.urls")),
    url(r'^api/user/', include("AuthDemo.urls")),
    url(r'^api/(?P<version>[v1|v2]+)/', include("VersionDemo.urls")),
]        
DRFDemo/DRFDemo/urls.py
from django.conf.urls import url, include
from django.contrib import admin
from .views import RegisterView, LoginView, TestView, PermissionView

urlpatterns = [
    url(r'^register', RegisterView.as_view()),
    url(r'^login', LoginView.as_view()),
    url(r'^test', TestView.as_view()),
    url(r'^permission', PermissionView.as_view()),

]        
DRFDemo/AuthDemo/urls.py
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import User
import uuid
from utils.auth import MyAuth
from utils.permission import MyPermission

# Create your views here.


class RegisterView(APIView):
    def post(self, request):
        name = request.data.get("name", "")
        pwd = request.data.get("pwd", "")
        if name and pwd:
            User.objects.create(name=name, pwd=pwd)
            return Response("註冊成功")
        return Response("用戶名或密碼不合法")        
        
class LoginView(APIView):
    def post(self, request):
        name = request.data.get("name", "")
        pwd = request.data.get("pwd", "")
        user_obj = User.objects.filter(name=name, pwd=pwd).first()
        if user_obj:
            # 登陸成功 建立一個token並給前端返回
            token = uuid.uuid4()
            user_obj.token = token
            user_obj.save()
            return Response(token)
        return Response("用戶名或密碼錯誤")        

class TestView(APIView):
    authentication_classes = [MyAuth, ]

    def get(self, request):
        print(request.user)
        print(request.user.name)
        print(request.auth)
        return Response("登陸後發送的數據")


class PermissionView(APIView):
    authentication_classes = [MyAuth, ]
    permission_classes = [MyPermission, ]

    def get(self, request):
        # 這個接口只能vip或者vvip訪問
        return Response("權限測試接口")        
DRFDemo/AuthDemo/views.py
REST_FRAMEWORK = {
    # "DEFAULT_VERSIONING_CLASS": "utils.version.MyVersion",
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
    'DEFAULT_VERSION': "v1",
    'ALLOWED_VERSIONS': ["v1", "v2"],
    'VERSION_PARAM': 'version',
    # 配置認證類
    # "DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth", ]
}
DRFDemo/DRFDemo/settings.py
from rest_framework import permissions


class MyPermission(permissions.BasePermission):
    message = "請充VIP,999一年"

    def has_permission(self, request, view):
        # 判斷用戶是否有權限
        if request.user.type in [1, 3]:
            return True
        return False        
        
DRFDemo/utils/permission.py
from django.db import models

# Create your models here.


class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    token = models.UUIDField(null=True, blank=True)
    CHOICES = ((1, "vip"), (2, "普通用戶"), (3, "vvip"))
    type = models.IntegerField(choices=CHOICES, default=2)
DRFDemo/AuthDemo/models.py
相關文章
相關標籤/搜索