一. 视图集与路由的使用

  使用视图集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. Mapreduce案例之找共同好友

    数据准备: A:B,C,D,F,E,OB:A,C,E,KC:F,A,D,ID:A,E,F,LE:B,C,D,M,LF:A,B,C,D,E,O,MG:A,C,D,E,FH:A,C,D,E,OI:A,OJ ...

  2. appium自动化 - android

    1. 获取driver appium通过生成driver来识别和操作app的UI元素.生成driver时,需要给出被测设备的相关信息.appium官方上的例子如下: https://github.co ...

  3. Boosting算法(一)

    本章全部来自于李航的<统计学>以及他的博客和自己试验.仅供个人复习使用. Boosting算法通过改变训练样本的权重,学习多个分类器,并将这些分类器进行线性组合,提高分类性能.我们以Ada ...

  4. django + ckeditor + 七牛云,图片上传到七牛云

    传送门 本人使用的是 Django 的自带的管理后台,安装 ckeditor 富文本编辑器后,上传图片的时候直接传到七牛云的.

  5. <<代码大全>>阅读笔记之二 变量名的力量

    1.变量命名的注意事项 1)可理解性 变量要望文知义,看到这个变量不用看其他的代码就知道这个变量表示什么意思 好的变量命:currentDate, heartRate 糟糕的变量名:newButton ...

  6. vue_03总结

    vue_03总结 1.组件: html.css.js的集合体 vue实例就代表组件 组件用template实例成员管理html结构,有且只有一个根标签 子组件可以复用,所以数据要组件化处理,data的 ...

  7. CWnd与HWND,GetSafeHwnd()与m_hWnd

    HWND是Windows系统中的窗口句柄,CWnd是MFC中的窗体类,两者的所属不同.CWnd对HWND进行了封装类,更加高级也更加简化. HWND是Window内核处理对象,系统通过HWND进行操作 ...

  8. 用JavaScript实现快排

    啥是快排这里就不讲了,主要还是把原来c++学的东西抓紧转化过来 快排运用的是分而治之的思想,确定一个中值,把大的放右边,小的放左边,然后再左右分别对左右的左右(雾)进行处理 需要注意的一点是,这玩意远 ...

  9. LA 6972 Domination

    6972 Domination Edward is the headmaster of Marjar University. He is enthusiastic about chess and of ...

  10. HDU 3081 Marriage Match II 最大流OR二分匹配

    Marriage Match IIHDU - 3081 题目大意:每个女孩子可以和没有与她或者是她的朋友有过争吵的男孩子交男朋友,现在玩一个游戏,每一轮每个女孩子都要交一个新的男朋友,问最多可以玩多少 ...