当前位置:网站首页>drf路由组件Routers

drf路由组件Routers

2022-08-02 14:01:00 意大利面拌42号混凝土

drf路由组件Routers

对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。

REST framework提供了两个router

  • SimpleRouter
  • DefaultRouter

一、使用方法

创建Router对象,并注册视图集

# 导入SimpleRouter与DafaultRouter包
from rest_farmework.routers import SimpleRouter,DafaultRouter

# 实例化对象
simplerouter = SimpleRouter()
defaultrouter = DafaultRouter()

# 路由注册
simplerouter.register('login/',StudentModelViewSet,basename='login')

register(prefix, viewset, base_name)

  • prefix 该视图集的路由前缀
  • viewset 视图集
  • base_name 路由别名的前缀

如上述代码会形成的路由如下:

^books/$    name: book-list
^books/{
    pk}/$   name: book-detail

二、添加路由的两种方式

有两种添加方式

第一种

urlpatterns = [
    ……
]
urlpatterns+=simplerouter.urls

第二种

urlpatterns = [
    path('',include(simplerouter.urls))
]

代码演示

# 必须是继承ModelViewSet的视图类才能自动生成路由
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class StudentModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
		# 这种方法不会自动生成,需要用action配置
    def login(self,request):
        """学生登录功能"""
        print(self.action)
        return Response({
    "message":"登录成功"})

路由代码

from django.urls import path, re_path
from . import views
urlpatterns = [
    ...
]

"""使用drf提供路由类router给视图集生成路由列表"""
# 实例化路由类
# drf提供一共提供了两个路由类给我们使用,他们用法一致,功能几乎一样
from rest_framework.routers import DefaultRouter
router = DefaultRouter()

# 注册视图集
# router.register("路由前缀",视图集类)
router.register("router_stu",views.StudentModelViewSet)

# 把生成的路由列表追加到urlpatterns
print( router.urls )
urlpatterns += router.urls

上面的代码就成功生成了路由地址[增/删/改/查一条/查多条的功能],但是不会自动我们在视图集自定义方法的路由。

所以我们如果也要给自定义方法生成路由,则需要进行action动作的声明。

1、自动生成路由的视图类
	-需要继承ViewSetMixin+9个视图子类
    -需要继承ViewSetMixin+视图类+五个视图扩展类

三、视图集中附加action的声明

在视图集中,如果想要让Router自动帮助我们为自定义的动作生成路由信息,需要使用rest_framework.decorators.action装饰器。

以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。

action装饰器可以接收两个参数:

  • methods: 声明该action对应的请求方式,列表传递

  • detail: 声明该action的路径是否与单一资源对应,及是否是

  • 访问的路径,可以不写,如果不写,以方法名作为路径 通过get请求访问这个路径test/login就能触发login的执行

  • url_path:访问的路径可以不写,,如果不写就会以方法名作为路径,通过get请求访问这个路径test/login就能触发函数login的执行

  • url_name:别名

# @action(methods=['GET'],detail=False,url_path='login',url_name='login')
@action(methods=['GET'],detail=True)
def login(self, request,pk):
    print(self.action)
    print(pk)
    # self.get_serializer()
    return Response('登录成功')

四、drf认证功能Authentication

1、自定义认证类

需要单独新建一个py文件,编写认证类

#自定义认证类,要继承BaseAuthentication,重写authenticate,如果认证通过,返回两个值,如果认证失败,抛认证失败的异常
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from .models import UserToken


class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        # 校验用户是否登录:看它有没有带token来,以及token是不是合法的(是不是我给的)
        token = request.GET.get('token')
        # 校验token是否合法(根据token去库中查询是否存在,如果存在,就是登陆了,放行)
        user_token = UserToken.objects.filter(token=token).first()
        if user_token:
            # 带的token是有效的
            # user_token.user当前登录用户
            return user_token.user, token
        else:
            raise AuthenticationFailed('token不合法或没有迭代token')
            

认证类的使用

#局部配置
from app01.auth import LoginAuth
class PublishView(ModelViewSet):
    authentication_classes = [LoginAuth,]
# 全局配置
REST_FRAMEWORK={
    
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.auth.LoginAuth",]
}

认证失败会有两种可能的返回值:

  • 401 Unauthorized 未认证
  • 403 Permission Denied 权限被禁止

2、内置认证类(需要配合权限使用)

可以在配置文件中配置全局默认的认证方案

REST_FRAMEWORK = {
    
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',  # session认证
        'rest_framework.authentication.BasicAuthentication',   # 基本认证
    )
}

也可以在每个视图中通过局部设置authentication_classess属性来设置

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView

class ExampleView(APIView):
    # 类属性
    authentication_classes = [SessionAuthentication, BasicAuthentication]
    ...

五、drf权限功能Permissions

1、自定义权限类

权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
  • 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断

编写权限类

# 继承BasePermission,重写has_permission,如果有权限,就返回True,没有权限就返回False
from rest_framework.permissions import BasePermission


class PermissionUser(BasePermission):
    def has_permission(self, request, view):
        # 如果有权限,返回True
        if request.user.user_type == 1:
            return True  # 超级用户允许访问
        else:
            return False

权限类使用

#认证类的局部配置
from app01.auth import LoginAuth
class PublishView(ModelViewSet):
     # 权限类:publish的5个接口,必须超级用户才能访问
    permission_classes = [PermissionUser]
    
    
#全局使用
REST_FRAMEWORK={
    
    "DEFAULT_PERMISSION_CLASSES":["app01.auth.PermissionUser",]
}
如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部
- `.has_permission(self, request, view)`
  是否可以访问视图, view表示当前视图对象

- `.has_object_permission(self, request, view, obj)`
  是否可以访问数据对象, view表示当前视图, obj为数据对象

2、内置权限类

from rest_framework.permissions import AllowAny,IsAuthenticated,IsAdminUser,IsAuthenticatedOrReadOnly
- AllowAny 允许所有用户
- IsAuthenticated 仅通过认证的用户
- IsAdminUser 仅管理员用户
- IsAuthenticatedOrReadOnly 已经登陆认证的用户可以对数据进行增删改操作,没有登陆认证的只能查看数据。

全局使用

REST_FRAMEWORK = {
    
    ....
    
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}
  • 如未指名,则采用如下配置
'DEFAULT_PERMISSION_CLASSES': (
   'rest_framework.permissions.AllowAny',
)

局部使用在具体的视图中通过permission_classes属性来设置

from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = [IsAuthenticated,]
    ...

六、drf频率功能Throttling

1、自定义频率类

2、内置频率类

新建一个名为throttlings.py的文件,名字可以随便取,在里面写限流类

# 使用内置限流类SimpleRateThrottle
from rest_framework.throttling import SimpleRateThrottle
class MyThrottling(SimpleRateThrottle):
    # 类中书写一个属性
    scope = 'frequency'
	# 重写get_cache_key()方法
    def get_cache_key(self, request, view):
        #返回什么就以什么做限制,此处返回其父类中的get_ident()方法,get_ident()方法为其内置ip限流方法
        return self.get_ident(request)

使用方法

# 局部配置
from .serializers import Bookserializers
from .models import Book
from rest_framework.generics import ListCreateAPIView
# 导入自定义编写的限流py文件
from .throttlings import MyThrottling

class BookGenericViewSet(ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = Bookserializers
    # 使用throttle_classes类属性
    """ throttle_classes类属性在类APIView中 """
    throttle_classes = [MyThrottling,]
    
    
# 全局配置
REST_FRAMEWORK = {
    
    'DEFAULT_THROTTLE_RATES': {
    
        # key值是频率类中scop字段对应的值,value是访问次数限制
        'frequency': '3/m',
    }
}

七、drf过滤排序功能

首先要明确一点,过滤条件应是在请求地址中

过滤功能有三种,内置过滤功能,第三方的过滤功能和自定义过滤功能

1、内置过滤功能

rest-framework的filters模块有三个类BaseFilterBackend(基类),SearchFilter(过滤查询类),OrderingFilter(排序类)
# 直接导入内置过滤模块,并配置过滤类即可使用
from .serializers import Bookserializers
from .models import Book
from rest_framework.generics import ListCreateAPIView
from rest_framework.filters import SearchFilter

class BookGenericViewSet(ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = Bookserializers
    # 配置过滤类
    filter_backends = [SearchFilter,]
    # 配置过滤字段
    search_fields=['name'] # url:http://127.0.0.1:8000/book/?search=记
    # 也可以配置多重字段,多种条件一起过滤
    search_fields=['name','price'] # url:http://127.0.0.1:8000/book/?search=记&search=56

2、内置排序功能

# 直接导入内置过滤模块,并配置排序类类即可使用
from .serializers import Bookserializers
from .models import Book
from rest_framework.generics import ListCreateAPIView
from rest_framework.filters import OrderingFilter

class BookGenericViewSet(ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = Bookserializers
    # 配置排序类
    filter_backends = [OrderingFilter,]
    # 配置排序字段
    # search_fields=['name']
    ordering_fields=['price'] # http://127.0.0.1:8000/book/?ordering=price (按价格的正序排列)
    ordering_fields = ['price','id'] # http://127.0.0.1:8000/book/?ordering=price,-id (价格一样,按照id的倒叙排列)

3、过滤排序组合使用

# 过滤排序组合使用
from .serializers import Bookserializers
from .models import Book
from rest_framework.generics import ListCreateAPIView
from rest_framework.filters import SearchFilter,OrderingFilter

class BookGenericViewSet(ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = Bookserializers
    # 配置过滤与排序类
    filter_backends = [SearchFilter,OrderingFilter]
    # 配置过滤字段
    search_fields = ['name']
    # 配置排序字段
    ordering_fields = ['price']  # url:http://127.0.0.1:8000/book/?search=记&ordering=-price

4、第三方过滤类的使用

现在我们有这么个需求,我想要价格为56且名字等于西游记的具体数据,怎么办?

http://127.0.0.1:8000/book/?search=西游记&price=56,就现有学习的内容无法实现此功能,这就需要借助于第三方的模块

pip install django-filter
from django_filters.rest_framework import DjangoFilterBackend
# 第三方过滤类的使用
from .serializers import Bookserializers
from .models import Book
from rest_framework.generics import ListCreateAPIView
from django_filters.rest_framework import DjangoFilterBackend

class BookGenericViewSet(ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = Bookserializers
	# 配置过滤字段
    filter_backends = [DjangoFilterBackend]
    filter_fields = ['name','price']  # url: http://127.0.0.1:8000/book/?name=西游记&price=56
1、自定义过滤类

新建一个过滤FilterBackend.py文件

# 自定义过滤类
from rest_framework.filters import BaseFilterBackend

class MyFilterBackend(BaseFilterBackend):
    # url: http://127.0.0.1:8000/book/?price__gt=56
    def filter_queryset(self, request, queryset, view):
        # queryset就是要过滤的数据
        price= request.query_params.get('price__gt')
        if price:
            queryset = queryset.filter(price__gt=price)

        return queryset

view.py

# 自定义过滤类的使用
from .serializers import Bookserializers
from .models import Book
from rest_framework.generics import ListCreateAPIView
from .FilterBackend import MyFilterBackend

class BookGenericViewSet(ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = Bookserializers
    filter_backends = [MyFilterBackend]

八、drf分页功能

############## 自定义分页类
##基本分页
from rest_framework.pagination import  PageNumberPagination,LimitOffsetPagination,CursorPagination
##基本分页
class MyPageNumberPagination(PageNumberPagination):
    # 重写4个类属性即可
    page_size = 2  # 每页显示两条
    page_query_param = 'page'  # 查询条件 http://127.0.0.1:8000/books/?page=2
    page_size_query_param = 'size'  # http://127.0.0.1:8000/books/?page=2&size=4 获取第二页数据,返回4条
    max_page_size = 5               # http://127.0.0.1:8000/books/?page=2&size=400 获取第二页数据,最多返回5条

# 偏移分页
class MyLimitOffsetPagination(LimitOffsetPagination):
    # 4个类属性
    default_limit = 2   #每页默认显示多少条
    limit_query_param = 'limit' # http://127.0.0.1:8000/books/?limit=3
    offset_query_param = 'offset'# http://127.0.0.1:8000/books/?limit=3&offset=1 # 从2位置取3条数据
    max_limit = 5   # 限制limit最大条数

# 游标分页
class MyCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'  # 查询条件,无用
    page_size = 2  # 每页显示多少条
    ordering = 'id' #按谁排序
原网站

版权声明
本文为[意大利面拌42号混凝土]所创,转载请带上原文链接,感谢
https://blog.csdn.net/prigilm/article/details/121150837