认证组件、权限组件、频率组件、过滤排序、分页

一、认证组件

有的接口需要登录后才能访问,有的接口,不登录就能访问,这时我们就需要用到【登录认证的限制】

需求

# 写一个登录接口,返回token,以后只要带着token过来,就是登录了,不带,就是没有登录

# 查询所有,不需要登录就能访问
# 查询单个,需要登录才能访问

1.认证组件使用步骤

1.写一个认证类,继承BaseAuthentication
2.重写authentication方法,在该方法中实现登录认证:token在哪带的?如果认证它就是登录了
3.如果认证成功,返回两个值【返回None或两个值】
4.认证不通过,抛异常AuthenticationFailed
5.局部使用和全局使用
	局部:只在某个视图类中使用【当前视图类管理的所有接口】
    	class BookDetailView(ViewSetMixin, RetrieveAPIView):
            authentication_classes = [LoginAuth] 
	
    全局:全局接口都生效(登录接口不要)
    	REST_FRAMEWORK = {
    	'DEFAULT_AUTHENTICATION_CLASSES':['app01.authenticate.LoginAuth']
	}
    
    局部禁用:
    	class BookDetailView(ViewSetMixin, RetrieveAPIView):
            authentication_classes = [] 

2.代码

views
from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from .models import User, UserToken, Book
from rest_framework.response import Response
import uuid
from .serializer import BookSerializer
from .authenticate import LoginAuth


# 登录接口  自动生成路由+由于登录功能,不用序列化,继承ViewSet
class UserView(ViewSet):
    @action(methods=['POST'], detail=False)
    def login(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user = User.objects.filter(username=username, password=password).first()
        if user:
            # 用户存在,登录成功
            # 生成一个随机字符串--uuid
            token = str(uuid.uuid4())  # 生成一个永不重复的随机字符串
            # 在userToken表中存储一下:1 从来没有登录过,插入一条,     2 登录过,修改记录
            # 如果有就修改,如果没有就新增  (if 自己写)
            # kwargs 传入的东西查找,能找到,使用defaults的更新,否则新增一条
            UserToken.objects.update_or_create(user=user, defaults={'token': token})
            return Response({'code': '100', 'msg': '登录成功', 'token': token})
        else:
            return Response({'code': '101', 'msg': '用户名或密码错误'})
        
from rest_framework.generics import ListAPIView,RetrieveAPIView
from rest_framework.viewsets import ViewSetMixin
from rest_framework.mixins import RetrieveModelMixin   


# 查询所有
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer


# 查询单个
class BookDetailView(ViewSetMixin, RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # authentication_classes = [LoginAuth]  # 需要写一个认证类,需要咱们写
认证类代码
class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        # 在这里实现认证,如果是登录的,继续往后走返回两个值,如果不是抛异常
        # 请求中是否携带token,判断是否登录,放在地址栏中
        token = request.query_params.get('token', None)
        if token:  # 前端传入token了,去表中查,如果能查到,登录了,返回两个值[固定的:当前登录用户,token]
            user_token = UserToken.objects.filter(token=token).first()
            if user_token:
                return user_token.user, token
            else:
                # 没有登录抛异常
                raise AuthenticationFailed('token认证失败')
        else:
            raise AuthenticationFailed('token没传')
路由代码
rom django.urls import path, include
from app01 import views
from rest_framework.routers import SimpleRouter

router = SimpleRouter()
router.register('user', views.UserView, 'user')
router.register('books', views.BookView, 'books')
router.register('books', views.BookDetailView, 'books')

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include(router.urls))
]

二、权限组件

权限组件就是当我们登录成功了,有些接口还是不能访问,因为没有权限

需求

查询单个和查询所有,都需要登录才能访问---》全局认证
	-查询单个,需要超级管理员才能访问
    -查询所有,所有用户都能访问
    
'''权限是一个字段,在User表中,加入user_type字段'''

1.权限的使用

1.写一个权限类,继承BasePermission
2.重写has_permission方法,在该方法中实现权限认证,在这方法中,request.user就是当前登录用户
3.如果有权限,返回True
4.没有权限,返回False,定制返回的中文:self.message='中文'
5.局部使用和全局使用
	-局部:只在某个视图类中使用【当前视图类管理的所有接口】
    	class BookDetailView(ViewSetMixin, RetrieveAPIView):
            permission_classes = [CommonPermission]
            
	-全局:全局所有接口都生效
          REST_FRAMEWORK = {
            'DEFAULT_PERMISSION_CLASSES': [
                'app01.permissions.CommonPermission',
            ],

        }
    
    -局部禁用:
    	 class BookDetailView(ViewSetMixin, RetrieveAPIView):
            permission_classes = [] 

2.权限代码

permission.py
# 写权限类,写一个类,继承基类BasePermission,重写has_permission方法,在方法中实现权限认证,如果有权限return True ,如果没有权限,返回False
from rest_framework.permissions import BasePermission


class CommonPermission(BasePermission):
    def has_permission(self, request, view):
        # 实现权限的控制  ---》知道当前登录用户是谁?当前登录用户是  request.user
        if request.user.user_type == 1:
            return True
        else:
            # 没有权限,向对象中放一个属性 message
            # 如果表模型中,使用了choice,就可以通过  get_字段名_display()  拿到choice对应的中文
            self.message = '您是【%s】,您没有权限' % request.user.get_user_type_display()
            return False

三、频率组件

主要作用是控制某个接口访问频率(次数)

需求

查询所有接口,同一个ip一分钟只能访问5次

1.使用步骤

# 1 写一个频率类,继承SimpleRateThrottle
# 2 重写get_cache_key方法,返回什么,就以什么做限制----》ip,用户id做限制
# 3 配置一个类属性:scope = 'book_5_m'
# 4 在配置文件中配置
  'DEFAULT_THROTTLE_RATES': {
        'book_5_m': '5/m',
    },
# 5 局部使用和全局使用
	-局部:只在某个视图类中使用【当前视图类管理的所有接口】
        class BookDetailView(ViewSetMixin, RetrieveAPIView):
    		throttle_classes = [CommonThrottle]
    -全局:全局所有接口都生效
          REST_FRAMEWORK = {
             'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.CommonThrottle'],

        }
    
    -局部禁用:
    	 class BookDetailView(ViewSetMixin, RetrieveAPIView):
            throttle_classes = [] 

2.频率代码

throttling.py
# 频率类,不继承BaseThrottle,继承SimpleRateThrottle,少写代码
from rest_framework.throttling import BaseThrottle, SimpleRateThrottle


class CommonThrottle(SimpleRateThrottle):
    # 类属性,属性值随便写
    # 配置文件中配置
    scope = 'book_5_m'

    def get_cache_key(self, request, view):
        # 返回什么,就以什么做频率限制【可以返回ip  或用户ID】
        # 客户端的ip地址从哪里拿?
        return request.META.get('REMOTE_ADDR')  # 以ip做限制
        # return request.user.pk  # 以用户id做限制

四、过滤排序

restful规范中,要求了请求地址带过滤条件
	-5个接口中,只有一个接口需要有过滤和排序,查询所有接口

需求

查询所有图书接口,查询以'红'开头的所有图书

1.内置过滤类的使用【继承了GenericAPIView】

class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    #  SearchFilter内置的,固定用法,模糊匹配
    #  就有过滤功能了,指定按哪个字段过滤
    filter_backends = [SearchFilter]
    # search_fields = ['name']  # 可以按名字模糊匹配
    search_fields = ['name','price']  # 可以按名字模糊匹配或价格模糊匹配
    
 # 可以使用的搜索方式
	http://127.0.0.1:8000/api/v1/books/?search=红  # name或price中只要有红就会搜出来

2.使用第三方django-filter实现过滤

# 安装:django-filter
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = []
    authentication_classes = []
    throttle_classes = []
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name','price']  # 支持完整匹配  name=聊斋11&price=933
    
    
 # 支持的查询方式
http://127.0.0.1:8000/api/v1/books/?price=939
http://127.0.0.1:8000/api/v1/books/?price=939&name=红楼猛

3.自己定制过滤类实现过滤

# 查询价格大于100的所有图书
	http://127.0.0.1:8000/api/v1/books/?price_gt=100
            
            
            
 #第一步; 定义一个过滤类,继承BaseFilterBackend,重写filter_queryset方法
class CommonFilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        # 在里面实现过滤,返回qs对象,就是过滤后的数据
        price_gt = request.query_params.get('price_gt', None)
        if price_gt:
            qs = queryset.filter(price__gt=int(price_gt))
            return qs

        else:
            return queryset
        
 # 第二步:配置在视图类上
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    filter_backends = [CommonFilter]  # 可以定制多个,从左往右,依次执行

4.排序的使用

# 内置的就够了
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [OrderingFilter]  
    ordering_fields = ['price']
    
 # 支持的查询方法:
    http://127.0.0.1:8000/api/v1/books/?ordering=price
    http://127.0.0.1:8000/api/v1/books/?ordering=-price
   http://127.0.0.1:8000/api/v1/books/?ordering=-id,price

五、分页

#  分页,只有查询所有接口,才有分页

# drf内置了三个分页器,对应三种分页方式

#内置的分页类不能直接使用,需要继承,定制一些参数后才能使用



# 分页使用,自定义一个分页类(三种)
class CommonPageNumberPagination(PageNumberPagination):
    page_size = 2  # 每页显示2条
    page_query_param = 'page'  # page=10  查询第10页的数据,每页显示2条
    page_size_query_param = 'size'  # page=10&size=5    查询第10页,每页显示5条
    max_page_size = 5  # 每页最大显示10条


# LimitOffset
class CommonLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 3  # 每页显示2条
    limit_query_param = 'limit'  # limit=3   取3条
    offset_query_param = 'offset'  # offset=1  从第一个位置开始,取limit条
    max_limit = 5
    # offset=3&limit=2      0  1 2 3 4 5


# app 用下面

class CommonCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'  # 查询参数
    page_size = 2  # 每页多少条
    ordering = 'id'  # 排序字段
# 配置在视图类上即可
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = []
    authentication_classes = []
    throttle_classes = []
    # 之前的东西一样用 ,内置的分页类不能直接使用,需要继承,定制一些参数后才能使用
    # pagination_class = PageNumberPagination
    #基本分页方式(基本是这种,网页端):http://127.0.0.1:8000/api/v1/books/?page=2&size=3

    # pagination_class = LimitOffsetPagination
    # 偏移分页 http://127.0.0.1:8000/api/v1/books/?limit=4&offset=1
    # 从第一条开始,取4条

    pagination_class = CommonCursorPagination
    # 游标分页,只能下一页,上一页,不能跳到中间,但它的效率最高,大数据量分页,使用这种较好
posted @ 2023-02-07 20:32  dear丹  阅读(25)  评论(0编辑  收藏  举报