首页 > 其他分享 >drf-认证、权限、频率、过滤、排序、分页

drf-认证、权限、频率、过滤、排序、分页

时间:2023-04-24 20:55:29浏览次数:49  
标签:排序 py queryset token objects 权限 class serializer drf

1.认证组件

1.1 局部认证

1.首先写两个接口,一个查询单个一个查询所有,我们利用视图扩展类和视图子类写在一个视图类上:
views.py:
from rest_framework.viewsets import ViewSetMixin
from rest_framework.generics import ListAPIView
from rest_framework.mixins import RetrieveModelMixin

class BookView(ViewSetMixin,ListAPIView,RetrieveModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
# ViewSetMixin:负责自动生成路由
# ListAPIView:继承扩展类ListModelMixin,里面有list方法
# RetrieveModelMixin:里面有retrieve方法

serializer.py:
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name','price','publish','authors','publish_detail','author_detail']
        extra_kwargs = {
            'name':{'max_length':8},
            'price': {'max_length': 8},
            'publish_detail':{'read_only':True},
            'author_detail':{'read_only':True},
            'publish':{'write_only':True},
            'authors':{'write_only':True}
        }
        
models.py:
class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)

class UserToken(models.Model):
    token = models.CharField(max_length=64)
    user = models.OneToOneField(to='User',on_delete=models.CASCADE)
"""
写在两个视图类上按照以下写法:
"""
views.py:
class BookView(ViewSetMixin,ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer


class BookDetailView(ViewSetMixin,RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
#   RetrieveAPIView继承RetrieveModelMixin和GenericAPIView,GenericAPIView中有queryset和serializer_class方法,所以继承RetrieveAPIView不继承RetrieveModelMixin。
models.py、serializer.py和之前一样

2.接下来我们想在查询单个图书接口上加上认证组件:
	1.写一个认证类,继承BaseAuthentication
	2.重写authenticate方法,拿到请求的数据(GET请求请求体当中不能携带数据,一般选用在请求头和地址栏当中携带数据),用该数据在数据库UserToken表中查找
	3.如果认证成功则返回两个值:用户对象和随机字符串token。认证失败则抛出异常AuthenticationFailed。 
	4.局部使用:
		class BookDetailView(ViewSetMixin,RetrieveAPIView):   			authentication_classes = [LoginAuth]			    
        
3.代码:
authenticate.py:
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from .models import UserToken

class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        token = request.query_params.get('token')
        if 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未上传')

views.py:
class BookDetailView(ViewSetMixin,RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    authentication_classes = [LoginAuth]
"""
authentication_classes是在:RetrieveAPIView>>>GenericAPIView>>>APIView中,在APIView中完成了三大认证。
"""   
serializer.py和models.py中代码未变

1.2 全局认证

在setting.py中设置:
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['app01.authenticate.LoginAuth']
}
此时我们发现即使是登陆也需要上传uuid字符串,不符合逻辑,需要在登陆类免除登录设置:
views.py:
class UserView(ViewSet):
    # 局部解除全局限制
    authentication_classes = []
    @action(methods=['POST'],detail=False,url_path='login',url_name='login')
    def login(self,request):
        username = request.data.get('username')
        password = request.data.get('password')
        user_obj = User.objects.filter(username=username,password=password).first()
        if user_obj:
            token = str(uuid.uuid4())
            UserToken.objects.update_or_create(user=user_obj,defaults={'token':token})
            return Response({'code':100,'msg':'登陆成功','token':token})
        else:
            return Response({'code':101,'msg':'用户名或密码错误'})

class BookView(ViewSetMixin,ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer


class BookDetailView(ViewSetMixin,RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

2.权限组件

2.1 局部权限

1.在某些软件上即使登陆成功,也不能访问,因为没有权限。这是由于在user表中增加了一个字段,用来区分是普通用户还是管理员(会员)。

2.步骤:
	1 写一个权限类,继承BasePermission
	2 重写has_permission方法,在该方法在中实现权限认证,在这方法中,request.user就是当前登录用户
	3 如果有权限,返回True
	4 没有权限,返回False,定制返回的中文: self.message='中文'
	5 局部使用和全局使用
    
3.代码:
models.py:
class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    user_type = models.IntegerField(choices=((1,'超级会员'),(2,'普通用户')),default=2)
    
permissions.py:
from rest_framework.permissions import BasePermission

class MyPermission(BasePermission):
    def has_permission(self, request, view):
        if request.user.user_type == 1:
            return True
        else:
            # self.message是定制的中文提示
            self.message = '您是%s,无权访问' % request.user.get_user_type_display()
        # get_字段名_display()可以拿到字段中choice中的注释
            return False

views.py:
class BookDetailView(ViewSetMixin,RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    authentication_classes = [LoginAuth]
    permission_classes = [MyPermission]

2.2 全局权限

如果很多视图类都要执行该权限,可以在设置中设置全局权限,并且可以对指定的视图类免除该权限:
settings.py:
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ['app01.permissions.MyPermission']
}

views.py:
class BookDetailView(ViewSetMixin,RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    authentication_classes = [LoginAuth]
    # 局部禁用
    permission_classes = []
permissions.py同上
"""
如果我们用原生的认证和权限,完成该功能:只有登录的用户并且上传token需要配合原生的认证类和权限类使用:
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated

class CarModelView(ModelViewSet):
    queryset = CarMode.objects.all()
    serializer_class = CarModelSerializer
    authentication_classes = [JSONWebTokenAuthentication]  # 校验token有没有传
    permission_classes = [IsAuthenticated]  # 校验是否登陆
"""

3.频率组件

3.1 局部频率限制

1.方法:
	1.写一个频率类,继承SimpleRateThrottle
	2.重写get_cache_key方法,返回什么,就以什么做限制(一般以用户ip地址和id做限制)
	3.配置一个类属性:scope = 'zkz'
	4.在配置文件中配置:m:每分钟;h:每小时;d:每天
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES': {
        'zkz': '3/m',
    }
}
2.代码:
throttling.py:
from rest_framework.throttling import SimpleRateThrottle

class MyThrottle(SimpleRateThrottle):
    scope = 'zkz'
    def get_cache_key(self, request, view):
        # 拿到客户端的ip地址
        #  print(request.META.get('REMOTE_ADDR'))  # 127.0.0.1 本机访问是127.0.0.1
        return request.META.get('REMOTE_ADDR')
"""
从地址栏取数据:request.query_params.get('token')
从原生django的cookie中取:request.COOKIE.get('sessioned')
get请求从请求头中取:request.META.get('HTTP_TOKEN')(前端的请求头键是token,经过了包装)
"""
  
views.py:
class BookDetailView(ViewSetMixin,RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    authentication_classes = [LoginAuth]
    permission_classes = [MyPermission]
    throttle_classes = [MyThrottle]
    
settings.py:
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES': {
        'zkz': '3/m',
    }
}

3.2 全局频率限制

settings.py:
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES': {
        'zkz': '3/m',
    },
    'DEFAULT_THROTTLE_CLASSES':
        ['app01.throttling.MyThrottle'],
}
视图类中如果不需要频率限制只需要修改:throttle_classes = []

4.过滤

4.1 过滤

只有查询所有才有过滤
方式一:必须要继承GenericAPIView及其子类:
from rest_framework.filters import SearchFilter
class BookView(ViewSetMixin,ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [SearchFilter]
    search_fields=['name']
访问的路由要修改成:?search=xxx
eg:?search=三:表示name字段中带有san自的数据对象都可以被筛选出来

"""
search_fields也可以上传多个字段,多个字段内如果都有待匹配的字段,都可以匹配得到:
search_fields=['name','price']
"""


方式二:
利用django-filter模块:可以多个条件同时匹配:
views.py:
from django_filters.rest_framework import DjangoFilterBackend
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name', 'price']

方式三:利用自定义过滤器:自定义一个py文件:filter.py,在里面编写过去条件,返回值是queryset
filter.py:
from rest_framework.filters import BaseFilterBackend

class MyFilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        # 可以自定义大于或者小于
        price = request.query_params.get('price__gt',None)
        if price:
            return queryset.filter(price__gt=price)
        else:
            return queryset
        
views.py:
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [MyFilter]  # 可以定制多个,从左往右排

5.排序

from rest_framework.filters import OrderingFilter

class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # 可以先过滤在排序,也可以先排序在过滤,也可以只排序或过滤
    filter_backends = [MyFilter,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:降序

"""
也可以按照多个字段排序:
ordering_fields = ['id','price']
路由:http://127.0.0.1:8000/api/v1/books/?ordering=price,-id:按照价格升序,按照id降序
"""

6.分页

方式一:自定义一个分页类:
mypage.py:
from rest_framework.pagination import PageNumberPagination

class MyPage(PageNumberPagination):
    page_size = 2  # 每页显示2条
    page_query_param = 'page'  # page=10:查询第10页的数据
    page_size_query_param = 'size'  # page=10&size=5:查询10页每页显示5条
    max_page_size = 5  # 每页最大显示条数
    
views.py:
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [MyFilter,OrderingFilter]
    ordering_fields = ['id','price']
    # pagination_class只能选一种,所以不能加列表
    pagination_class = MyPage

方式二:
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
    
方式三:
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
    # 游标分页,只能下一页,上一页,不能跳到中间,但它的效率最高,大数据量分页,使用这种较好

标签:排序,py,queryset,token,objects,权限,class,serializer,drf
From: https://www.cnblogs.com/ERROR404Notfound/p/17099902.html

相关文章

  • drf-jwt、simplejwt的使用
    1.接口文档#前后端分离 -我们做后端,写接口-前端做前端,根据接口写app,pc,小程序-作为后端来讲,我们很清楚,比如登录接口/api/v1/login/---->post---->username,password编码方式json----》返回的格式{code:100,msg:登录成功}-后端人员,接口写完,一......
  • 1.8 冒泡排序
    第一部曲:从头到尾扫描数组的数,进行n-1轮,每次进行n-i次比较,因为经过前面i次,后面i个数已经确定了大小,不用再参与比较,如果后面的数大与前面的数就交换,第一轮结束后就把最大的数放在了最后,后面继续比较。需要注意两个数交换的时候要引入一个中间数,利用中间数才能进行交换。第二部曲:......
  • 其它权限校验方法 自定义权限校验方法
    我们前面都是使用@PreAuthorize注解,然后在在其中使用的是hasAuthority方法进行校验。SpringSecurity还为我们提供了其它方法例如:hasAnyAuthority,hasRole,hasAnyRole等。​这里我们先不急着去介绍这些方法,我们先去理解hasAuthority的原理,然后再去学习其他方法你就更容易理解,而不是......
  • LeetCode 周赛 342(2023/04/23)容斥原理、计数排序、滑动窗口、子数组 GCB
    本文已收录到AndroidFamily,技术和职场问题,请关注公众号[彭旭锐]提问。大家好,我是小彭。前天刚举办2023年力扣杯个人SOLO赛,昨天周赛就出了一场Easy-Easy-Medium-Medium的水场,不得不说LeetCode是懂礼数的......
  • 数据库查询权限信息代码实现
    ​我们只需要根据用户id去查询到其所对应的权限信息即可​所以我们可以先定义个mapper,其中提供一个方法可以根据userid查询权限信息创建对应的mapper文件,定义对应的sql语句 在application.yml中配置mapperXML文件的位置 ​然后我们可以在UserDetailsServiceImpl中去调......
  • 从数据库查询权限信息 准备工作
     RBAC权限模型(Role-BasedAccessControl)即:基于角色的权限控制。这是目前最常被开发者使用也是相对易用、通用权限模型 准备工作创建数据库表CREATETABLE`sys_menu`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`menu_name`varchar(64)NOTNULLDEFAULT'NULL'COMME......
  • java中排序的正确用法
    publicclassTest{publicstaticvoidmain(String[]args){sort();}publicstaticvoidsort(){List<Integer>list=newArrayList();//降序hitRule.sort((o1,o2)->o2.compareTo(o1));//升序......
  • drf之请求request与response
    目录Request可解析编码格式定制传入数据类型格式方法一,使用parser_classes定制方法二,使用settings.py配置优先级说明Response方法一,在类中定义Response返回格式方法二,在settings.py中定义返回格式优先级说明Responseinit可以传入的参数Request可解析编码格式request可以解析三......
  • 快速排序_C语言
    思路:base:取最低位为basej:从右向左找到比base小的数,放到第i位。i++i:从左向右找到比base大的数,放到第j位。j--当i==j时,base放到第i位,此时base左面都是小于base的,base右边都是大于base的递归:只要最低位小于最高位,执行递归代码#include<stdio.h>//作用:打印数组......
  • 自定义权限校验方法、基于配置的权限控制、CSRF
    自定义权限校验方法我们也可以定义自己的权限校验方法。在@PreAuthorize注解中使用我们的方法。创建expression包,在该包下创建SGEexpression类@Component("ex")publicclassSGEexpression{publicbooleanhasAuthority(Stringauthority){//获取当前用户......