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