首页 > 编程语言 >python之路65 drf从入门到成神 5 认证组件、权限组件、频率组件、过滤排序、分页

python之路65 drf从入门到成神 5 认证组件、权限组件、频率组件、过滤排序、分页

时间:2023-02-07 20:45:06浏览次数:42  
标签:python price 成神 ViewSetMixin token user 组件 import class

认证组件

以后,有的接口需要登录后才能访问,有的接口,不登录就能访问

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


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

认证组件使用步骤

1.写一个认证类,继承BaseAuthentication
2.重写authenticate方法,在该方法中实现登录认证:token在哪带的?如果认证它就是登录了
3.如果认证成功,返回两个值【返回None或两个值】
4.认证不通过,抛异常AuthenticationFailed
5.局部使用和全局使用
    局部:只在某个视图类中使用【当前视图类管理的所有接口】
	from rest_framework.viewsets import ViewSetMixin
	from rest_framework.generics import ListAPIView, RetrieveAPIView
	from .authenticate import LoginAuth
	class BookDetailView(ViewSetMixin, RetrieveAPIView):
		queryset = Book.objects.all()
		serializer_class = BookSerializer
		authentication_classes = [LoginAuth]

     全局:全局索引接口都生效(登录接口不要)
	REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES':['app01.authenticate.LoginAuth']
}
      
     局部禁用:
	class BookDetailView(ViewSetMixin, RetrieveAPIView):
            authentication_classes = []

代码

视图
from rest_framework.viewsets import ViewSetMixin
from rest_framework.generics import ListAPIView, RetrieveAPIView
from .authenticate import LoginAuth


# 查询所有
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # authentication_classes = []  #  这个是局部禁用


# 查询单个
class BookDetailView(ViewSetMixin, RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    authentication_classes = [LoginAuth]  # 需要认证类 自己写


认证类代码
from rest_framework.authentication import BaseAuthentication
from .models import UserToken
from rest_framework.exceptions import AuthenticationFailed
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没传')


路由代码
from django.contrib import admin
from django.urls import path, include
from app01 import views
from rest_framework.routers import SimpleRouter, DefaultRouter

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.写一个权限类,继承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 = [] 

代码

需要增肌一个user_type字段
权限类
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
            self.message = '您是【%s】 您没有权限' % request.user.get_user_type_display()
            return False

视图代码
from .permissions import CommonPermission
class BookDetailView(ViewSetMixin, RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [CommonPermission]  # 权限类 其他和认证代码一致 局部和全局配置必须有一个 执行顺序局部优先

频率组件

控制某个接口访问频率(次数)

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

使用步骤

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 = []

频率代码

频率类
# 频率类 不继承BaseThrottle 继承SimpleRateThrottle
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle

class CommonThrottle(SimpleRateThrottle):
    # 写个类属性
    scope = 'lqz'

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

        return request.user.pk  # 以用户id做限制

配置文件中的配置和属性scope有关
    # 全局 频率配置
    # 'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.CommonThrottle'],
    'DEFAULT_THROTTLE_RATES': {
        'lqz': '5/m',
    },

视图类代码
from .throttling import CommonThrottle
class BookDetailView(ViewSetMixin, RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    throttle_classes = [CommonThrottle]

过滤排序

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

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

继承APIView 伪代码

class BookView(APIView):
    def get(self,request):
        search=request.query_params.get('search')
        books=Book.objects.filter()

继承APIView如何写,完全自己写,麻烦,但是清晰

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

from rest_framework.filters import SearchFilter
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中只要有红就会搜出来


使用第三方django—filter实现过滤

安装django-filter
pip3.8 install django-filter -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

'''
注意:django版本会自动升级为最新版本  需要修改回来
'''
再执行一下

pip3.8 install django==2.2.2 -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

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=万历十五年&price=444


支持的查询方式(完整查询)
http://127.0.0.1:8000/api/v1/books/?price=939
http://127.0.0.1:8000/api/v1/books/?price=22&name=红楼梦

自己定制过滤类实现过滤

查询价格大于100的所有图书
     http://127.0.0.1:8000/api/v1/books/?price_gt=100


第一步; 定义一个过滤类,继承BaseFilterBackend,重写filter_queryset方法
from rest_framework.filters import BaseFilterBackend
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

第二步:配置在视图类上
from .filter import CommonFilter
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [CommonFilter]  # 可以定制多个,从左往右,依次执行



自己定制的类 在视图类下可以添加另外两种过滤方式(SearchFilter,DjangoFilterBackend)的编写 但是要加上过滤的字段 
内置过滤类 : search_fields = ['name', 'price']   # 可以按名字模糊匹配
第三方过滤类:filterset_fields = ['name', 'price']  # 支持完整匹配,

排序的使用

在过滤的基础上加上排序
from rest_framework.filters import SearchFilter,OrderingFilter
from .filter import CommonFilter
# 查询所有
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    filter_backends = [CommonFilter,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内置了三个分页器,对应三种分页方式
内置的分页类不能直接使用,需要继承 定制一些参数后才能使用




标签:python,price,成神,ViewSetMixin,token,user,组件,import,class
From: https://www.cnblogs.com/xm15/p/17099749.html

相关文章