一. 视图集与路由的使用

  使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:

  • list() 提供一组数据

  • retrieve() 提供单个数据

  • create() 创建数据

  • update() 保存数据

  • destory() 删除数据

  ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。

  视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。

  1. 常用的视图集父类

  1.ViewSet

  继承自APIView 与 ViewSetMixin作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

  ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{'get':'list'})的映射处理工作。

  在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

  2.GenericViewSet

  使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView。

  GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView与ViewSetMixin,在实现了调用as_view()时传入字典(如{'get':'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

  3.ModelViewSet

  继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

  4.ReadOnlyModelViewSet

  继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。

  下面我们还是通过案例,为大家演示吧!

  首先,先创建一个子应用。

python3 manage.py startapp collect
  5. 在collect下新建序列化器类
# collect下的serializers.py文件

from students.models import Student
from rest_framework import serializers class StudentModelSerializer(serializers.ModelSerializer): class Meta:
model = Student
fields = ["id", "name", "age", "sex"]
extra_kwargs = {
"name": {"max_length": 10, "min_length": 4},
"age": {"max_value": 150, "min_value": 0},
} def validate_name(self, data):
if data == "root":
raise serializers.ValidationError("用户名不能为root!")
return data def validate(self, attrs):
name = attrs.get('name')
age = attrs.get('age') if name == "alex" and age == 22:
raise serializers.ValidationError("alex在22时的故事。。。") return attrs class StudentInfoModelSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = ["id", "name"]
  6. collect下的urls.py
from django.urls import path, re_path
from collect import views urlpatterns = [
# 不要在同一个路由的as_view中书写两个同样的键的http请求,会产生覆盖!!!
# ViewSet
path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
path('student1/get_5_girl/', views.Student1ViewSet.as_view({"get": "get_5_girl"})),
re_path(r'^student1/(?P<pk>\d+)/$', views.Student1ViewSet.as_view({"get": "get_one"})),
# GenericViewSet
path('student2/', views.Student3GenericViewSet.as_view({"get": "get_5"})),
path('student2/get_5_girl/', views.Student3GenericViewSet.as_view({"get": "get_5_girl"})),
# GenericViewSet,可以和模型类进行组合快速生成基本的API接口
path("students3/", views.Student4GenericViewSet.as_view({"get": "list", "post": "create"})),
# ModelViewSet 默认提供了5个API接口
path("students4/", views.Student5ModelViewSet.as_view({"post": "create", "get": "list"})),
re_path(r"^students4/(?P<pk>\d+)/$", views.Student5ModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
# ReadOnlyModelViewSet
path("students5/", views.Student6ReadOnlyModelViewSet.as_view({"get": "list"})),
re_path(r"^students5/(?P<pk>\d+)/$", views.Student6ReadOnlyModelViewSet.as_view({"get": "retrieve"})), # 一个视图类中调用多个序列化器
path("student8/", views.Student8GenericAPIView.as_view()), # 一个视图集中调用多个序列化器
path("student9/", views.Student9ModelViewSet.as_view({"get": "list"})),
re_path(r"^student9/(?P<pk>\d+)/$", views.Student9ModelViewSet.as_view({"get": "retrieve"})),
] """
有了视图集以后,视图文件中多个视图类可以合并成一个,但是,路由的代码就变得复杂了,
需要我们经常在as_view方法 ,编写http请求和视图方法的对应关系,
事实上,在路由中,DRF也提供了一个路由类给我们对路由的代码进行简写。
当然,这个路由类仅针对于 视图集 才可以使用。
""" # 路由类默认只会给视图集中的基本5个API生成地址[ 获取一条,获取多条,添加.删除,修改数据 ]
from rest_framework.routers import DefaultRouter
# 实例化路由类
router = DefaultRouter()
# router.register("访问地址前缀","视图集类","访问别名")
# 注册视图视图集类
router.register("student7", views.Student7ModelViewSet) # 把路由列表注册到django项目中
urlpatterns += router.urls
  7. collect下的views.py
"""ViewSet视图集,继承于APIView,所以APIView有的功能,它都有,APIView没有的功能,它也没有"""
from rest_framework.viewsets import ViewSet
from students.models import Student
from .serializers import StudentModelSerializer
from rest_framework.response import Response class Student1ViewSet(ViewSet):
def get_5(self, request):
student_list = Student.objects.all()[:5] serializer = StudentModelSerializer(instance=student_list, many=True) return Response(serializer.data) def get_one(self, request, pk):
student = Student.objects.get(pk=pk) serializer = StudentModelSerializer(instance=student) return Response(serializer.data) def get_5_girl(self, request):
student_list = Student.objects.filter(sex=False)[:5] serializer = StudentModelSerializer(instance=student_list, many=True) return Response(serializer.data) """如果希望在视图集中调用GenericAPIView的功能,则可以采用下面方式"""
from rest_framework.generics import GenericAPIView class Student2ViewSet(ViewSet, GenericAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer def get_5(self, request):
student_list = self.get_queryset()[:5] serializer = StudentModelSerializer(instance=student_list, many=True) return Response(serializer.data) def get_one(self, request, pk):
student = self.get_object() serializer = StudentModelSerializer(instance=student) return Response(serializer.data) def get_5_girl(self, request):
student_list = self.get_queryset().filter(sex=False)[:5] serializer = StudentModelSerializer(instance=student_list, many=True) return Response(serializer.data) """
上面的方式,虽然实现视图集中调用GenericAPIView,但是我们要多了一些类的继承。
所以我们可以直接继承 GenericViewSet
"""
from rest_framework.viewsets import GenericViewSet class Student3GenericViewSet(GenericViewSet):
serializer_class = StudentModelSerializer
queryset = Student.objects.all() def get_5(self, request):
student_list = self.get_queryset()[:5] serializer = self.get_serializer(instance=student_list, many=True) return Response(serializer.data) def get_5_girl(self, request):
student_list = self.get_queryset().filter(sex=False)[:5] serializer = self.get_serializer(instance=student_list, many=True) return Response(serializer.data) """
在使用GenericViewSet时,虽然已经提供了基本调用数据集(queryset)和序列化器属性,但是我们要编写一些基本的
API时,还是需要调用DRF提供的模型扩展类 [Mixins]
"""
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin class Student4GenericViewSet(GenericViewSet, ListModelMixin, CreateModelMixin):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer from rest_framework.viewsets import ModelViewSet class Student5ModelViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer # 只读模型视图集
from rest_framework.viewsets import ReadOnlyModelViewSet class Student6ReadOnlyModelViewSet(ReadOnlyModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer # 路由的使用
from rest_framework.decorators import action class Student7ModelViewSet(ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer # methods 指定允许哪些http请求访问当前视图方法
# detail 指定生成的路由地址中是否要夹带pk值,True为需要
@action(methods=["GET"], detail=False)
def get_6(self, request):
serilizer = self.get_serializer(instance=self.get_queryset().get(pk=6))
return Response(serilizer.data) """在多个视图类合并成一个视图类以后,那么有时候会出现一个类中需要调用多个序列化器""" """1. 在视图类中调用多个序列化器"""
"""原来的视图类中基本上一个视图类只会调用一个序列化器,当然也有可能要调用多个序列化器"""
from .serializers import StudentInfoModelSerializer class Student8GenericAPIView(GenericAPIView):
queryset = Student.objects.all() # GenericAPI内部调用序列化器的方法,我们可以重写这个方法来实现根据不同的需求来调用不同的序列化器
def get_serializer_class(self):
if self.request.method == "GET":
# 2个字段
return StudentInfoModelSerializer
return StudentModelSerializer def get(self, request):
"""获取所有数据的id和name"""
student_list = self.get_queryset() serializer = self.get_serializer(instance=student_list, many=True) return Response(serializer.data) def post(self, request):
"""添加数据"""
data = request.data
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data) """2. 在一个视图集中调用多个序列化器""" class Student9ModelViewSet(ModelViewSet):
queryset = Student.objects.all() """要求:
列表数据list,返回2个字段,
详情数据retrieve,返回所有字段,
"""
def get_serializer_class(self):
# 本次客户端请求的视图方法名 self.action
if self.action == "list":
return StudentInfoModelSerializer
return StudentModelSerializer

二. 扩展功能

  为了方便接下来的学习,我们创建一个新的子应用 opt

python3 manage.py startapp opt

  因为接下来的功能中需要使用到登录功能,所以我们使用django内置admin站点并创建一个管理员.

  创建管理员以后,访问admin站点,先修改站点的语言配置,在settings里修改

LANGUAGE_CODE = 'zh-hans'

  1. 认证Authentication

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

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

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

  opt下的urls.py
from django.urls import path
from opt import views urlpatterns = [
path('auth1/', views.Demo1APIView.as_view()),
path('auth2/', views.Demo2APIView.as_view()),
]
  opt下的views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser """用户的认证和权限识别""" class Demo1APIView(APIView):
"""只允许登录后的用户访问"""
permission_classes = [IsAuthenticated] def get(self, request):
"""个人中心"""
return Response("个人中心") class Demo2APIView(APIView):
"""只允许管理员访问"""
permission_classes = [IsAdminUser] def get(self, request):
"""个人中心2"""
return Response("个人中心2")

  2. 权限Permissions

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

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断

  • 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断

  内置提供的权限:

  • AllowAny 允许所有用户

  • IsAuthenticated 仅通过认证的用户

  • IsAdminUser 仅管理员用户

  • IsAuthenticatedOrReadOnly 已经登陆认证的用户可以对数据进行增删改操作,没有登陆认证的只能查看数据。

  可以在配置文件中全局设置默认的权限管理类,如:

REST_FRAMEWORK = {
.... 'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}

  如果未指明,则采用如下默认配置

'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
)

  也可以在具体的视图中通过permission_classes属性来设置。

  opt下的urls.py
urlpatterns = [
path('auth1/', views.Demo1APIView.as_view()),
path('auth2/', views.Demo2APIView.as_view()),
# 自定义权限
path('auth3/', views.Demo3APIView.as_view()),
]
  opt下的views.py
# 自定义权限
from rest_framework.permissions import BasePermission class MyPermission(BasePermission):
def has_permission(self, request, view):
"""
针对访问视图进行权限判断
:param request: 本次操作的http请求对象
:param view: 本次访问路由对应的视图对象
:return:
"""
if request.user.username == "xiaoming":
return True
return False class Demo3APIView(APIView):
permission_classes = [MyPermission] def get(self, request):
"""个人中心3"""
return Response("个人中心3")

  3. 限流Throttling

  可以对接口访问的频次进行限制,以减轻服务器压力。

  一般用于付费购买次数,投票等场景使用.

  可以在配置文件中,使用DEFAULT_THROTTLE_CLASSES 和 DEFAULT_THROTTLE_RATES进行全局配置

REST_FRAMEWORK = {
# 限流
'DEFAULT_THROTTLE_CLASSES': ( # 对全局进行设置
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'anon': '3/hour',
'user': '3/minute',
}
}

  DEFAULT_THROTTLE_RATES 可以使用 second, minute, hour 或day来指明周期。

  也可以在具体视图中通过throttle_classess属性来配置

  opt下的urls.py
urlpatterns = [
path('auth1/', views.Demo1APIView.as_view()),
path('auth2/', views.Demo2APIView.as_view()),
# 自定义权限
path('auth3/', views.Demo3APIView.as_view()),
# 限流
path('auth4/', views.Demo4APIView.as_view()),
]
  opt下的views.py
# 限流
from rest_framework.throttling import UserRateThrottle, AnonRateThrottle class Demo4APIView(APIView):
# throttle_classes = [UserRateThrottle, AnonRateThrottle] # 全局配置后,这里就不用指定 def get(self, request):
"""投票页面"""
return Response("投票页面")

  4. 过滤Filtering

  对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。

pip3 install django-filter

  在配置文件里进行注册

INSTALLED_APPS = [
...
'django_filters', # 需要注册应用,
] REST_FRAMEWORK = {
...
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

  在视图中添加filter_fields属性,指定可以过滤的字段。

  opt下的urls.py
urlpatterns = [
path('auth1/', views.Demo1APIView.as_view()),
path('auth2/', views.Demo2APIView.as_view()),
# 自定义权限
path('auth3/', views.Demo3APIView.as_view()),
# 限流
path('auth4/', views.Demo4APIView.as_view()),
# 过滤
path('data5/', views.Demo5APIView.as_view()),
]
  opt下的views.py
# 过滤
from rest_framework.generics import GenericAPIView, ListAPIView
from students.models import Student
from .serializers import StudentModelSerializer
from django_filters.rest_framework import DjangoFilterBackend class Demo5APIView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
filter_backends = [DjangoFilterBackend] # 全局配置后,这里就不用指定了。
filter_fields = ['age', "id"] # 声明过滤字段

  5. 排序Ordering

  对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。

  使用方法:

  在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。

  前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。

  opt下的urs.py
urlpatterns = [
path('auth1/', views.Demo1APIView.as_view()),
path('auth2/', views.Demo2APIView.as_view()),
# 自定义权限
path('auth3/', views.Demo3APIView.as_view()),
# 限流
path('auth4/', views.Demo4APIView.as_view()),
# 过滤
path('data5/', views.Demo5APIView.as_view()),
# 排序
path('data6/', views.Demo6APIView.as_view()),
]
  opt下的views.py
# 排序
from rest_framework.filters import OrderingFilter class Demo6APIView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
filter_backends = [DjangoFilterBackend, OrderingFilter] # 局部配置会覆盖全局配置
filter_fields = ['id', "sex"]
ordering_fields = ['id', "age"]

  6. 分页Pagination

  REST framework提供了分页的支持。

  我们可以在配置文件中设置全局的分页方式,如:

REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100 # 每页数目
}

  也可通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas属性来指明。

  opt下的urls.py
urlpatterns = [
path('auth1/', views.Demo1APIView.as_view()),
path('auth2/', views.Demo2APIView.as_view()),
# 自定义权限
path('auth3/', views.Demo3APIView.as_view()),
# 限流
path('auth4/', views.Demo4APIView.as_view()),
# 过滤
path('data5/', views.Demo5APIView.as_view()),
# 排序
path('data6/', views.Demo6APIView.as_view()),
# 分页
path('data7/', views.Demo7APIView.as_view()),
]
  opt下的views.py
# 分页
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination """1. 自定义分页器,定制分页的相关配置"""
"""
# 页码分页 PageNumberPagination
前端访问形式:GET http://127.0.0.1:8000/opt/data7/?page=4 page=1 limit 0,10
page=2 limit 10,20 # 偏移量分页 LimitOffsetPagination
前端访问形式:GET http://127.0.0.1:8000/opt/data7/?start=4&size=3 start=0 limit 0,10
start=10 limit 10,10
start=20 limit 20,10
""" class StandardPageNumberPagination(PageNumberPagination):
"""分页相关配置"""
page_query_param = "page" # 设置分页页码关键字名
page_size = 3 # 设置每页显示数据条数
page_size_query_param = "size" # 设置指定每页大小的关键字名
max_page_size = 5 # 设置每页显示最大值 class StandardLimitOffsetPagination(LimitOffsetPagination):
default_limit = 2 # 默认限制,默认值与PAGE_SIZE设置一致
limit_query_param = "size" # limit参数名
offset_query_param = "start" # offset参数名
max_limit = 5 # 最大limit限制 class Demo7APIView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
# 分页
# 页码分页类
pagination_class = StandardPageNumberPagination
# 偏移量分页类
# pagination_class = StandardLimitOffsetPagination

  注意:如果在视图内关闭分页功能,只需在视图内设置

pagination_class = None

Django-DRF(路由与扩展功能)的更多相关文章

  1. Django drf:cbv源码、resful规范及接口、drf使用、response源码、序列化

    一.cbv源码分析 二.resful规范 三.django中写resful的借口 四.drf写resful的借口 五.APIVIew源码分析 六.drf之序列化 一.cbv源码分析 -CBV和FBV ...

  2. drf路由分发、解析/渲染模块配置、使用admin、自动序列化配置

    目录 drf路由分发配置 解析模块配置 渲染模块配置 浏览器渲染打开 浏览器渲染关闭 结论 drf使用后台admin drf序列化模块 serializers.py: views.py:单查群查 测试 ...

  3. django DRF理解

    django restframework(DRF) 最近的开发过程当中,发现restframework的功能很强大,所以尝试解读了一下源码,写篇博客分享给大家,有错误的地方还请各位多多指出 视图部分 ...

  4. Django DRF 分页

    Django DRF 分页 分页在DRF当中可以一共有三种,可以通过setttings设置,也可也通过自定义设置 PageNumberPagination 使用URL http://127.0.0.1 ...

  5. django的路由系统

    在django生成的工程项目文件中urls.py文件用于指定路由信息 该文件默认导入以下模块 from confimport from import admin from confimport url ...

  6. django之路由层

    一 Django中路由的作用 二 简单的路由配置 三 有名分组 四 路由分发 五 反向解析 六 名称空间 七 django2.0版的path 一 Django中路由的作用 URL配置(URLconf) ...

  7. 解决Django + DRF:403 FORBIDDEN:CSRF令牌丢失或不正确,{"detail":"CSRF Failed: CSRF cookie not set."}

    我有一个Android客户端应用程序尝试使用Django + DRF后端进行身份验证.但是,当我尝试登录时,我收到以下响应: 403: CSRF Failed: CSRF token missing ...

  8. Python学习(三十一)—— Django之路由系统

    转载自:http://www.cnblogs.com/liwenzhou/p/8271147.html Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLc ...

  9. Django之路由

    Django的路由系统 URL配置(URLconf)就像Django所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表. 我们就是以这种方式告诉Django,遇到哪个URL的时 ...

  10. Django之路由系统 Dj

    Django之路由系统   Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调 ...

随机推荐

  1. Wind Simulation in 'God of War'(GDC2019 战神4风力场模拟)

    Wind Simulation in 'God of War'(GDC2019) 战神4中的风力场模拟 这次带来的分享的主题是,圣莫妮卡工作室他们在战神4中关于GPU模拟风力场. 演讲者Rupert ...

  2. BZOJ 2124 (线段树 + hash)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2124 题意:给一个1到N的排列{Ai},询问是否存在1<=p1<p2< ...

  3. 【LuoguP4482】[BJWC2018]Border 的四种求法

    题目链接 题意 区间 boder \(n,q\leq 2*10^5\) Sol (暴力哈希/SA可以水过) 字符串区间询问问题,考虑用 \(SAM\) 解决. boder相当于是询问区间 \([l,r ...

  4. vscode 远程编辑文件

    操作 安装扩展 remote-vscode 配置ssh 转发: 添加 RemoteForward 52698 127.0.0.1:52698 到 ~/.ssh/config: # Read more ...

  5. 多线程:Thread类的Join()方法

    多线程:Thread类的Join()方法 http://blog.163.com/hc_ranxu/blog/static/3672318220095284513678/ 当我们在线程B中调用Thre ...

  6. mac使用php-version切换PHP版本

    在开发过程中,有时候我们的程序对某个php版本有着极为重要的限制,特别是大型项目. 因此,我们就需要切换多个php版本来满足我们的需求. 我们使用php-version来达到这个目的. 首先我们先使用 ...

  7. php 一段 shmop

    $size = 1024*1024; $shm_key = ftok(__FILE__, 't'); $shm_id = shmop_open($shm_key, "c", 064 ...

  8. OpenGL 开发环境配置:Visual Studio 2017 + GLFW + GLEW

    Step1:Visual Studio 2017 Why 开发环境,后面编译GLFW 和 GLEW也要用 How 这里使用的是Visual Studio 2017的 Community 版本,直接官网 ...

  9. mybatis 多级级联(多级嵌套)

    注:笔者这里的嵌套可以用词有点欠缺,忘见谅 需求:用一个查询接口查出其结果集,这里就用伪代码标识要返回前端的类与类之间的关系. class 顶层{ String otherValue; LinkedL ...

  10. Linux网络编程六、报文解析(1)

    一.pcap文件解析 依赖的库:libpcap,头文件:pcap/pcap.h 获取pcap文件:tcpdump,-i:指定监听接口,默认配置好的最小的号码的接口.-w:指定存入文件,将原始报文存入指 ...