zoukankan      html  css  js  c++  java
  • DRF(三) 认证组件

    基于权限角色的认证

    三表(一对多)


    五表(多对多)


    六表(Django)

    用户不通过角色获得权限, 直接获得权限, 第六张表为用户表和权限表的多对多关系表


    auth源码解析

    /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/contrib/auth/__init__.py


    核心代码: return django_apps.get_model(settings.AUTH_USER_MODEL, require_ready=False)

    Django_apps 来源: from django.apps import apps as django_apps

    apps来源: /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/apps/registry.py


    方法get_model来源:


    app_label 的值就是 settings.AUTH_USER_MODEL,而settings对象则是有 global_settings.py里的属性

    from django.conf import global_settings
    
    class LazySettings(LazyObject):
          def configure(self, default_settings=global_settings, **options):
            """
            Called to manually configure the settings. The 'default_settings'
            parameter sets where to retrieve any unspecified values from (its
            argument must support attribute access (__getattr__)).
            """
            if self._wrapped is not empty:
                raise RuntimeError('Settings already configured.')
            holder = UserSettingsHolder(default_settings)
            for name, value in options.items():
                if not name.isupper():
                    raise TypeError('Setting %r must be uppercase.' % name)
                setattr(holder, name, value)
            self._wrapped = holder
    
    settings = LazySettings()
    

    查看到global_settings.py 中, AUTH_USER_MODEL = 'auth.User'


    /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/contrib/auth/models.py

    • User类


    • AbstractUser类, 继承 AbstractBaseUser, PermissionsMixin类


    • PermissionsMixin类

      groups: 角色多对多字段

      user_permissions:用户权限多对多字段


    • Group类

      permissions: 角色权限多对多字段


    案例

    创建models类

    from django.db import models
    
    # Create your models here.
    
    # 基于Django auth(基于角色权限认证六表)的User表设计 - 扩展字段
    from django.contrib.auth.models import AbstractUser
    
    
    # 用户角色多对多字段 - groups(反向 user_set)
    # 用户权限多对多字段 - user_permissions (反向 user_set)
    # 角色权限多对多字段 - permissions (反向)
    class User(AbstractUser):
        telephone = models.CharField(max_length=11)
    
        class Meta:
            db_table = 'auth_user'
            verbose_name = '用户'
            verbose_name_plural = '用户'
    
        def __str__(self):
            return self.username
    
    
    class Car(models.Model):
        name = models.CharField(max_length=64)
        price = models.DecimalField(max_digits=10, decimal_places=2)
        brand = models.IntegerField(choices=((0, '宝马'), (1, '奔驰'), (2, '迈巴赫'), (3, '路虎')), default=0)
        is_delete = models.BooleanField(default=0)
    
        class Meta:
            db_table = 'auth_car'
            verbose_name = '汽车'
            verbose_name_plural = '汽车'
    
        def __str__(self):
            return self.name
    
        def brandName(self):
            return self.get_brand_display()
    

    数据库迁移完成查看是否有telephone字段



    注册models

    admin.py

    from django.contrib import admin
    from django.contrib.auth.admin import UserAdmin
    
    
    from api import models
    
    # Register your models here.
    
    # admin注册自定义User设置了UserAdmin就可以秘文操作密码
    admin.site.register(models.User, UserAdmin)
    admin.site.register(models.Car)
    

    编写接口

    • urls.py
    from django.urls import path, re_path
    from api import views
    
    urlpatterns = [
        path('cars/', views.CarModelViewSet.as_view({'get': 'list', 'post': 'create'})),
        re_path('cars/(?P<pk>.*)/$', views.CarModelViewSet.as_view(
            {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
    ]
    

    • serializers.py
    from rest_framework.serializers import ModelSerializer
    from api import models
    
    
    class CarsModelSerializer(ModelSerializer):
        class Meta:
            model = models.Car
            fields = ('name', 'price', 'brand', 'brandName')
            extra_kwargs = {
                'brand': {
                    'write_only': True
                }
            }
    

    • views.py
    from rest_framework.viewsets import ModelViewSet
    from api import models, serializers
    from rest_framework.response import Response
    
    
    class CarModelViewSet(ModelViewSet):
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    

    测试orm

    import os, django
    
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoAuth.settings')
    django.setup()
    
    from api.models import User
    from django.contrib.auth.models import Group, Permission
    
    if __name__ == '__main__':
        # User表查询
        print(User.objects.get(id=2).username)
    
        # 查看id为2的用户的角色 <QuerySet [<Group: 管理员>]>
        print(User.objects.get(id=2).groups.all())
    
        #     查看id为2的用户的角色的名字
        print(User.objects.get(id=2).groups.first().name)
    
        #   查看id为2的用户的权限
        # <QuerySet [<Permission: api | 汽车 | Can add car>, <Permission: api | 汽车 | Can change car>, <Permission: api | 汽车 | Can delete car>]>
        print(User.objects.get(id=2).user_permissions.all())
    
        #     查看角色为管理员的用户 <QuerySet [<User: java>]>
        print(User.objects.filter(groups__name='管理员'))
    
        #     Group 表查询
        #     查看角色名  管理员
        print(Group.objects.first().name)
    
        #     查看角色对应的用户  <QuerySet [<User: java>]>
        print(Group.objects.first().user_set.all())
    
        # 查看角色对应的权限
        # <QuerySet [<Permission: api | 汽车 | Can add car>, <Permission: api | 汽车 | Can change car>, <Permission: api | 汽车 | Can delete car>]>
        print(Group.objects.first().permissions.all())
    
    # 权限表操作
    # 查询所有权限
    # <QuerySet [<Permission: admin | 日志记录 | Can add log entry>, <Permission: admin | 日志记录 | Can change log entry>, <Permission: admin | 日志记录 | Can delete log entry>, <Permission: admin | 日志记录 | Can view log entry>, <Permission: api | 汽车 | Can add car>, <Permission: api | 汽车 | Can change car>, <Permission: api | 汽车 | Can delete car>, <Permission: api | 汽车 | Can view car>, <Permission: api | 用户 | Can add user>, <Permission: api | 用户 | Can change user>, <Permission: api | 用户 | Can delete user>, <Permission: api | 用户 | Can view user>, <Permission: auth | 组 | Can add group>, <Permission: auth | 组 | Can change group>, <Permission: auth | 组 | Can delete group>, <Permission: auth | 组 | Can view group>, <Permission: auth | 权限 | Can add permission>, <Permission: auth | 权限 | Can change permission>, <Permission: auth | 权限 | Can delete permission>, <Permission: auth | 权限 | Can view permission>, '...(remaining elements truncated)...']>
    print(Permission.objects.all())
    
    # 查询 汽车添加权限权限,权限表中添加权限的id为25  <QuerySet [<User: java>]>
    print(Permission.objects.filter(pk=25).first().user_set.all())
    
    # 查询汽车添加权限对应的角色,权限表中添加权限的id为25  <QuerySet [<Group: 管理员>]>
    print(Permission.objects.filter(pk=25).first().group_set.all())
    

    添加drf 权限认证配置

    源码查看配置字段

    /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/settings.py


    源码认证解析

    /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/views.py


    • dispatch 方法


    • initial 方法


    • check_permissions 方法


    • get_permissions 方法


    • permission_classes 属性


    • DEFAULT_PERMISSION_CLASSES 属性

      /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/settings.py


    settings.py

    • 自定义认证类,重写authenticate方法(通过 返回 auth|user|None, 失败 抛异常)

      源码路径: `/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/sitepackages/rest_framework/authentication.py


    • 自定义权限类 重写has_permission方法 (通过True | 失败 False)

      源码路径: /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/permissions.py 下的has_permission方法

    # drf权限配置
    REST_FRAMEWORK = {
        # 自定义认证类, 重写authenticate方法(通过 返回 auth|user|None, 失败 抛异常
        'DEFAULT_AUTHENTICATION_CLASSES': [
            # 前台sessionid 和 后台 django_session 完成认证, 赋值给request.user
            # 'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.BasicAuthentication'
        ],
        # 自定义权限类, 重写has_permission方法 (通过True | 失败 False
        'DEFAULT_PERMISSION_CLASSES': [
            # 'rest_framework.permissions.AllowAny',  # 所有人都能登录, 前面的校验就没用了
            # 校验request.user
            # 'rest_framework.permissions.IsAuthenticated',
            #     查操作不校验request.user, 赠改删校验request.user
            'rest_framework.permissions.IsAuthenticatedOrReadOnly',
            #     是否是在职用户(request.user.is_staff), 校验is_staff字段是否为True
            'rest_framework.permissions.IsAdminUser',
        ]
    

    为什么 自定义认证类, 重写authenticate方法


    为什么 自定义权限类, 重写has_permission方法


    浏览器访问 http://127.0.0.1:8000/api/cars/,弹出登录界面


    为什么一个页面登录了也会跳出来登录界面

    因为在认证阶段没有用session作为认证, 所以即便是页面登录了也会跳出来需要登录的界面


    自定义权限认证

    在应用目录下新建permissions.py

    from rest_framework.permissions import BasePermission
    
    
    class isSuperUserBasePermission(BasePermission):
        def has_permission(self, request, view):
            return request.user and request.user.is_superuser
    
    
    class isGroupAdminBasePermission(BasePermission):
        def has_permission(self, request, view):
            return request.user and request.user.groups.filter(name='管理员')
    

    全局校验

    settings.py

    # drf权限配置
    REST_FRAMEWORK = {
        # 自定义认证类, 重写authenticate方法(通过 返回 auth|user|None, 失败 抛异常
        'DEFAULT_AUTHENTICATION_CLASSES': [
            # 前台sessionid 和 后台 django_session 完成认证, 赋值给request.user
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.BasicAuthentication'
        ],
        # 自定义权限类, 重写has_permission方法 (通过True | 失败 False
        'DEFAULT_PERMISSION_CLASSES': [
            # 'rest_framework.permissions.AllowAny',  # 所有人都能登录, 前面的校验就没用了
            # 校验request.user
            # 'rest_framework.permissions.IsAuthenticated',
            #     查操作不校验request.user, 赠改删校验request.user
            'rest_framework.permissions.IsAuthenticatedOrReadOnly',
            #     是否是在职用户(request.user.is_staff), 校验is_staff字段是否为True
            'rest_framework.permissions.IsAdminUser',
            #     自定义是否是超级管理员 (request.user.is_superuser)
            # 'api.permissions.isSuperUserBasePermission',
            # 自定义是否是管理员组员 (request.user.groups.filter(name='管理员'))
            'api.permissions.isGroupAdminBasePermission',
    
        ],
    }
    

    局部校验

    views.py

    from rest_framework.viewsets import ModelViewSet
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    

    jwt(json web tokens)

    django默认签发token

    Django 默认的请求是要通过rest_framework.authentication.SessionAuthentication 认证, 产生request.user的值

    这个过程中,客户端通过nginx请求到后台服务器,第一次登录,后台服务器将session记录写入数据库;第二次登录,后台服务器查询数据库验证得到user,存放到request.user这个属性中,有多少次登录, 后台服务器就有多少次和数据库之间的IO操作

    jwt

    组成

    头.体.签名

    头:{公司基本信息,加密方式} =》 base64加密

    载荷:{用户信息,过期时间} =》 base64加密

    签名:{头,载荷,密钥} =〉 hash256加密


    签发Token

    登录的用户,过期时间,服务器密钥 + 基础信息们


    • django中服务器的密钥


    校验Token

    前台的头 + 前台的载荷 + 服务器密钥


    DRF-JWT

    django提供的jwt

     pip3 install djangorestframework-jwt
    

    路由

    主urls.py

    from django.contrib import admin
    from django.urls import path, include
    from rest_framework_jwt.views import obtain_jwt_token
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/', include('api.urls')),
        # 登录接口
        path('login/', obtain_jwt_token),
    ]
    
    

    视图

    views.py局部校验

    from django.shortcuts import render
    from rest_framework.viewsets import ModelViewSet
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    

    postman测试返回token值


    自定义JWT登录

    路由

    主urls.py

    from django.contrib import admin
    from django.urls import path, include
    from api import views
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/', include('api.urls')),
        # 登录接口
        path('login/', views.loginAPIView.as_view()),
    ]
    

    视图

    views.py

    from rest_framework.response import Response
    from rest_framework.views import APIView
    from rest_framework_jwt.serializers import jwt_payload_handler
    from rest_framework_jwt.serializers import jwt_encode_handler
    from django.contrib import auth
    # 自定义jwt登录
    class loginAPIView(APIView):
        # jwtPayloadHandler = api_settings.JWT_PAYLOAD_HANDLER
        # jwtEncodeHandler = api_settings.JWT_ENCODE_HANDLER
    
        def post(self, request, *args, **kwargs):
            username = request.data.get('username')
            password = request.data.get('password')
            if not (username and password):
                return Response({
                    'error': 'username与password必须存在'
                })
    
            # 第一版代码
            # userObj = models.User.objects.filter(username=username, is_active=True).first()  # type: models.User
            # print(userObj)
            # print(userObj.check_password(password))
            # if not (userObj and userObj.check_password(password)):
            #     return Response({
            #         'error': 'username与password有误'
            #     })
    
            # 第二版代码
            userObj = auth.authenticate(username=username, is_active=True, password=password)
            if not userObj:
                return Response({
                            'error': 'username与password有误'
                        })
            #        签发token
            payload = jwt_payload_handler(userObj)
            token = jwt_encode_handler(payload)
    
            return Response({
                'status': 200,
                'msg': 'ok',
                'token': token,
    
            })
    

    postman测试


    jwt签发token源码

    jwt配置参考源码

    /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework_jwt/settings.py


    settings.py

    # jwt配置
    import datetime
    
    JWT_AUTH = {
        'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=3000),
        'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
    }
    

    views.py

    from rest_framework.viewsets import ModelViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 必须完成jwt校验才能得到登录状态
        authentication_classes = [JSONWebTokenAuthentication]
    
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    

    postman测试

    • 登录接口获取Token


    • 汽车接口加入header Authorization: jwt <token>


    如果不加入 header Authorization: jwt <token>


    自定义报错信息

    当登录认证的token过期时候, 会弹出如下报错

    这个时候如果要将这个报错自定义成中文, 就需要重新authentications.py 这个文件里的authenticate方法, 复制/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework_jwt/authentication.py到自己的应用目录下, 更名为authentications.py


    authentications.py

    import jwt
    from django.utils.encoding import smart_text
    
    from rest_framework import exceptions
    from rest_framework_jwt.settings import api_settings
    from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
    from rest_framework.authentication import (
        get_authorization_header
    )
    jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
    jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER
    
    
    class jwtAuthentication(BaseJSONWebTokenAuthentication):
        def get_jwt_value(self, request):
            auth = get_authorization_header(request).split()
            auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower()
    
            if not auth:
                if api_settings.JWT_AUTH_COOKIE:
                    return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE)
                return None
    
            if smart_text(auth[0].lower()) != auth_header_prefix:
                return None
    
            if len(auth) == 1:
                msg = _('Invalid Authorization header. No credentials provided.')
                raise exceptions.AuthenticationFailed(msg)
            elif len(auth) > 2:
                msg = _('Invalid Authorization header. Credentials string '
                        'should not contain spaces.')
                raise exceptions.AuthenticationFailed(msg)
    
            return auth[1]
    
    
        def authenticate(self, request):
            """
            Returns a two-tuple of `User` and token if a valid signature has been
            supplied using JWT-based authentication.  Otherwise returns `None`.
            """
            jwt_value = self.get_jwt_value(request)
            if jwt_value is None:
                return None
    
            try:
                payload = jwt_decode_handler(jwt_value)
            except jwt.ExpiredSignature:
                raise exceptions.AuthenticationFailed(f'Token {jwt_value}已过期')
            except jwt.InvalidTokenError:
                raise exceptions.AuthenticationFailed('Token非法')
    
            user = self.authenticate_credentials(payload)
    
            return (user, jwt_value)
    

    views.py

    默认使用JSONWebTokenAuthentication这个类 进行认证, 现在使用自定义的认证类jwtAuthentication

    from rest_framework.viewsets import ModelViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from api.authentications import jwtAuthentication
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 必须完成jwt校验才能得到登录状态
        # authentication_classes = [JSONWebTokenAuthentication]
        authentication_classes = [jwtAuthentication]
    
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    


    汽车接口测试

    新增(post)

    Headers


    Body



    查(get)


    过滤:django-filter

    安装

    pip3 install django-filter
    

    注册apps

    settings.py

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'api.apps.ApiConfig',
        'rest_framework',
        'django_filters'
    ]
    

    视图层配置过滤

    默认是and 查询

    views.py

    from rest_framework.viewsets import ModelViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from api.authentications import jwtAuthentication
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    from django_filters.rest_framework import DjangoFilterBackend
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 必须完成jwt校验才能得到登录状态
        # authentication_classes = [JSONWebTokenAuthentication]
        authentication_classes = [jwtAuthentication]
    
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    
    
    #     过滤
        filter_backends = [DjangoFilterBackend]
    # 一般过滤字段为分类字段
    #     filter_fields = ('brand', 'price')
        filterset_fields = ('brand', 'price')
    

    postman测试



    筛选

    视图层

    views.py

    from rest_framework.viewsets import ModelViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from api.authentications import jwtAuthentication
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework.filters import SearchFilter
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 必须完成jwt校验才能得到登录状态
        # authentication_classes = [JSONWebTokenAuthentication]
        authentication_classes = [jwtAuthentication]
    
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    
    
    #     过滤
    #     filter_backends = [DjangoFilterBackend]
    # 一般过滤字段为分类字段
    #     filter_fields = ('brand', 'price')
    #     filterset_fields = ('brand', 'price')
    
    #     筛选
        filter_backends = [DjangoFilterBackend, SearchFilter]
        search_fields = ('name', 'price')
    

    postman测试

    只能做单条件匹配


    排序


    修改代码

    修改serializers.py

    from rest_framework.serializers import ModelSerializer
    from api import models
    
    
    class CarsModelSerializer(ModelSerializer):
        class Meta:
            model = models.Car
            fields = ('id','name', 'price', 'brand', 'brandName')
    
            extra_kwargs = {
                'id': {
                    'read_only': True
                },
                'brand': {
                    'write_only': True
                }
            }
    

    Postman 查看get 请求能获得ID


    views.py

    from rest_framework.viewsets import ModelViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from api.authentications import jwtAuthentication
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework.filters import SearchFilter, OrderingFilter
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 必须完成jwt校验才能得到登录状态
        # authentication_classes = [JSONWebTokenAuthentication]
        authentication_classes = [jwtAuthentication]
    
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    
    
    #     过滤
    #     filter_backends = [DjangoFilterBackend]
    # 一般过滤字段为分类字段
    #     filter_fields = ('brand', 'price')
    #     filterset_fields = ('brand', 'price')
    
    #     筛选
    #     filter_backends = [DjangoFilterBackend, SearchFilter]
    #     search_fields = ('name', 'price')
    
    #     排序
        filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
        search_fields = ('name', 'price')
        ordering_fields = ('id',)
    


    分页

    基础分页

    在应用目录新建paginations.py

    from rest_framework import pagination
    
    class PageNumberPagination(pagination.PageNumberPagination):
        # 一页的条数
        page_size = 3
        # 接口最终选页码的字段名 - 一般不修改
        page_query_param = 'page'
    
        # 用户可以通过接口自定义一页条数  ?page=1&page_size=一页的条数
        page_size_query_param = 'page_size'
        # 用户可以自定义的最大一页条数, 超过就采用最大值
        max_page_size = 4
    

    views.py

    from rest_framework.viewsets import ModelViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from api.authentications import jwtAuthentication
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework.filters import SearchFilter, OrderingFilter
    from api import paginations
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 必须完成jwt校验才能得到登录状态
        # authentication_classes = [JSONWebTokenAuthentication]
        authentication_classes = [jwtAuthentication]
    
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    
    
    #     过滤
    #     filter_backends = [DjangoFilterBackend]
    # 一般过滤字段为分类字段
    #     filter_fields = ('brand', 'price')
    #     filterset_fields = ('brand', 'price')
    
    #     筛选
    #     filter_backends = [DjangoFilterBackend, SearchFilter]
    #     search_fields = ('name', 'price')
    
    #     排序
        filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
        search_fields = ('name', 'price')
        ordering_fields = ('id', 'price')
    
    #     分页
        pagination_class = paginations.PageNumberPagination
    



    偏移分页

    paginations.py

    from rest_framework import pagination
    
    # 偏移分页  接口:?offset=0&limit=3  从第一条往后查3条  limit  控制显示条数 offset 负责偏移
    class LimitOffsetPagination(pagination.LimitOffsetPagination):
        # 一页的条数
        default_limit = 2
        limit_query_param = 'limit'
        offset_query_param = 'offset'
        # 用户可以自定义最大的一项条数, 超过就采用最大值
        max_limit = 4
    

    views.py

    from rest_framework.viewsets import ModelViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from api.authentications import jwtAuthentication
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework.filters import SearchFilter, OrderingFilter
    from api import paginations
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 必须完成jwt校验才能得到登录状态
        # authentication_classes = [JSONWebTokenAuthentication]
        authentication_classes = [jwtAuthentication]
    
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    
    
    #     过滤
    #     filter_backends = [DjangoFilterBackend]
    # 一般过滤字段为分类字段
    #     filter_fields = ('brand', 'price')
    #     filterset_fields = ('brand', 'price')
    
    #     筛选
    #     filter_backends = [DjangoFilterBackend, SearchFilter]
    #     search_fields = ('name', 'price')
    
    #     排序
        filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
        search_fields = ('name', 'price')
        ordering_fields = ('id', 'price')
    
    #     基础分页: 配置一个类, 不是类们
    #     pagination_class = paginations.PageNumberPagination
    
    #     偏移分页
        pagination_class = paginations.LimitOffsetPagination
    



    加密分页

    paginations.py

    from rest_framework import pagination
    
    
    # 加密分页
    class CursorPagination(pagination.CursorPagination):
        # 一页的条数
        page_size = 2
        # 请求页码数据的字段 - 字段后的参数是加密的
        cursor_query_param = 'cursor'
        # 用户自定义一页的字段和最大值
        page_size_query_param = 'page_size'
        max_page_size = 4
        # 加密分页必须指定该字段 - 不能与drf的ordering组件同时使用
        ordering = 'id'
    

    views.py

    from rest_framework.viewsets import ModelViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from api.authentications import jwtAuthentication
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework.filters import SearchFilter, OrderingFilter
    from api import paginations
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 必须完成jwt校验才能得到登录状态
        # authentication_classes = [JSONWebTokenAuthentication]
        authentication_classes = [jwtAuthentication]
    
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            return Response('该功能暂无提供')
    
    
    #     过滤
    #     filter_backends = [DjangoFilterBackend]
    # 一般过滤字段为分类字段
    #     filter_fields = ('brand', 'price')
    #     filterset_fields = ('brand', 'price')
    
    #     筛选
    #     filter_backends = [DjangoFilterBackend, SearchFilter]
    #     search_fields = ('name', 'price')
    
    #     排序
    #     filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
        search_fields = ('name', 'price')
        ordering_fields = ('id', 'price')
    
    #     基础分页: 配置一个类, 不是类们
    #     pagination_class = paginations.PageNumberPagination
    
    #     偏移分页
    #     pagination_class = paginations.LimitOffsetPagination
    
    #     加密分页
        pagination_class = paginations.CursorPagination
    


    异常处理模块

    源码:/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/views.py


    自定义异常处理

    从源码中获得句柄名字,源码路径 /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/settings.py


    settings.py中添加句柄

    REST_FRAMEWORK = {
      # 异常句柄
        'EXCEPTION_HANDLER': 'api.exceptions.exception_handler'
    }
    

    在应用目录下新建 exceptions.py

    from rest_framework.response import Response
    from rest_framework.views import exception_handler as drf_exception_handler
    from rest_framework.status import HTTP_500_INTERNAL_SERVER_ERROR
    
    
    def exception_handler(exc, context):
        response = drf_exception_handler(exc, context)
    
        # drf没有提供处理服务器的异常
        if not response:
            return Response({'status': 500, 'msg': '服务器异常'}, headers=HTTP_500_INTERNAL_SERVER_ERROR)
    
        response.data = {
            'status': 444,
            'msg': response.data['detail']
        }
    
        return response
    


    views.py

    from rest_framework.viewsets import ModelViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from api.authentications import jwtAuthentication
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework.filters import SearchFilter, OrderingFilter
    from api import paginations
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 必须完成jwt校验才能得到登录状态
        # authentication_classes = [JSONWebTokenAuthentication]
        authentication_classes = [jwtAuthentication]
    
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            # return Response('该功能暂无提供')
            raise Exception(123)
            
    #     过滤
    #     filter_backends = [DjangoFilterBackend]
    # 一般过滤字段为分类字段
    #     filter_fields = ('brand', 'price')
    #     filterset_fields = ('brand', 'price')
    
    #     筛选
    #     filter_backends = [DjangoFilterBackend, SearchFilter]
    #     search_fields = ('name', 'price')
    
    #     排序
    #     filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
        search_fields = ('name', 'price')
        ordering_fields = ('id', 'price')
    
    #     基础分页: 配置一个类, 不是类们
    #     pagination_class = paginations.PageNumberPagination
    
    #     偏移分页
    #     pagination_class = paginations.LimitOffsetPagination
    
    #     加密分页
        pagination_class = paginations.CursorPagination
    

    postman测试


    未处理的异常

    exceptions.py

    from rest_framework.response import Response
    from rest_framework.views import exception_handler as drf_exception_handler
    from rest_framework.status import HTTP_500_INTERNAL_SERVER_ERROR
    
    
    def exception_handler(exc, context):
        response = drf_exception_handler(exc, context)
        print(response)
        # drf没有提供处理服务器的异常
        # if response is None:
        #     return Response({'status':500, 'msg': '服务器异常'}, status=HTTP_500_INTERNAL_SERVER_ERROR)
    
        response.data = {
            'status': 444,
            'msg': response.data['detail']
        }
    
        return response
    


    status=HTTP_500_INTERNAL_SERVER_ERROR 只能够处理raise 的异常

    如果把destroy方法下改成pass,无法处理该异常

    views.py

    from rest_framework.viewsets import ModelViewSet
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from api.authentications import jwtAuthentication
    from api import models, serializers
    from rest_framework.response import Response
    from api import permissions
    from rest_framework.permissions import IsAuthenticated
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework.filters import SearchFilter, OrderingFilter
    from api import paginations
    
    class CarModelViewSet(ModelViewSet):
        # 局部禁用
        # permission_classes = (permissions.isSuperUserBasePermission, )
        # 局部解禁
        # permission_classes = ()
        # 必须完成jwt校验才能得到登录状态
        # authentication_classes = [JSONWebTokenAuthentication]
        authentication_classes = [jwtAuthentication]
    
        # 登录后才能查看
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarsModelSerializer
    
        def destroy(self, request, *args, **kwargs):
            # return Response('该功能暂无提供')
            pass
    
    #     过滤
    #     filter_backends = [DjangoFilterBackend]
    # 一般过滤字段为分类字段
    #     filter_fields = ('brand', 'price')
    #     filterset_fields = ('brand', 'price')
    
    #     筛选
    #     filter_backends = [DjangoFilterBackend, SearchFilter]
    #     search_fields = ('name', 'price')
    
    #     排序
    #     filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
        search_fields = ('name', 'price')
        ordering_fields = ('id', 'price')
    
    #     基础分页: 配置一个类, 不是类们
    #     pagination_class = paginations.PageNumberPagination
    
    #     偏移分页
    #     pagination_class = paginations.LimitOffsetPagination
    
    #     加密分页
        pagination_class = paginations.CursorPagination
    


  • 相关阅读:
    MYSQL-----IFNULL()函数的用法
    《你的灯亮着吗?》读书笔记
    《测试架构师修炼之路》阅读笔记第三章
    未记录书名的一本营销书阅读记录
    Spring注解@Component、@Repository、@Service、@Controller区别
    PropertyPlaceholderConfigurer的用法:
    Jackson Streaming API to read and write JSON
    ParameterizedType的作用
    setTimeOut传参数(转)
    mybatis使用count返回int的方法
  • 原文地址:https://www.cnblogs.com/cjwnb/p/14410312.html
Copyright © 2011-2022 走看看