Django-DRF(路由与扩展功能)
一. 视图集与路由的使用
使用视图集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(路由与扩展功能)的更多相关文章
- Django drf:cbv源码、resful规范及接口、drf使用、response源码、序列化
一.cbv源码分析 二.resful规范 三.django中写resful的借口 四.drf写resful的借口 五.APIVIew源码分析 六.drf之序列化 一.cbv源码分析 -CBV和FBV ...
- drf路由分发、解析/渲染模块配置、使用admin、自动序列化配置
目录 drf路由分发配置 解析模块配置 渲染模块配置 浏览器渲染打开 浏览器渲染关闭 结论 drf使用后台admin drf序列化模块 serializers.py: views.py:单查群查 测试 ...
- django DRF理解
django restframework(DRF) 最近的开发过程当中,发现restframework的功能很强大,所以尝试解读了一下源码,写篇博客分享给大家,有错误的地方还请各位多多指出 视图部分 ...
- Django DRF 分页
Django DRF 分页 分页在DRF当中可以一共有三种,可以通过setttings设置,也可也通过自定义设置 PageNumberPagination 使用URL http://127.0.0.1 ...
- django的路由系统
在django生成的工程项目文件中urls.py文件用于指定路由信息 该文件默认导入以下模块 from confimport from import admin from confimport url ...
- django之路由层
一 Django中路由的作用 二 简单的路由配置 三 有名分组 四 路由分发 五 反向解析 六 名称空间 七 django2.0版的path 一 Django中路由的作用 URL配置(URLconf) ...
- 解决Django + DRF:403 FORBIDDEN:CSRF令牌丢失或不正确,{"detail":"CSRF Failed: CSRF cookie not set."}
我有一个Android客户端应用程序尝试使用Django + DRF后端进行身份验证.但是,当我尝试登录时,我收到以下响应: 403: CSRF Failed: CSRF token missing ...
- Python学习(三十一)—— Django之路由系统
转载自:http://www.cnblogs.com/liwenzhou/p/8271147.html Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLc ...
- Django之路由
Django的路由系统 URL配置(URLconf)就像Django所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表. 我们就是以这种方式告诉Django,遇到哪个URL的时 ...
- Django之路由系统 Dj
Django之路由系统 Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调 ...
随机推荐
- vulkan asynchronous compute
https://www.youtube.com/watch?v=XOGIDMJThto https://www.khronos.org/assets/uploads/developers/librar ...
- 16-SQLServer强制走索引
一.注意点 1.使用with(index(索引名称))来使SQL强制走索引. 二.示例截图 1.创建非聚集索引 2.不使用with,不走索引的截图 3.使用with,强制走索引的截图
- js中回调函数(callback)的一些理解
前言 我个人在学习Node.js相关知识时遇到了回调函数这个概念,虽然之前已经在c,c++等编程语言中用到过它,但还一直未对其机制有深入了解,这次就来好好谈一下它. 概念理解 百度对它的解释是回调函数 ...
- python内置函数(二)之filter,map,sorted
filter filter()函数接收一个函数 f 和一个iterable的对象,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条 ...
- [2019HDU多校第一场][HDU 6588][K. Function]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6588 题目大意:求\(\sum_{i=1}^{n}gcd(\left \lfloor \sqrt[3] ...
- 01 salt平台,软件架构图
1.前期调研 1.别人家的 https://www.cnblogs.com/ssyfj/p/9060367.html#top https://www.cnblogs.com/evilliu/artic ...
- mysql优化之SQL优化
https://www.cnblogs.com/binghou/p/9096610.html (SQL优化)
- 1、Mat类的属性、方法
Mat类分有两个部分:矩阵头和指向矩阵数据部分的指针 Mat类的属性: rows 矩阵的行数 cols 矩阵的列数 dims 矩阵的维度,例如5*6矩阵是二维矩阵,则dims=2,三维矩阵di ...
- vector 与 array
vector STL中的模板数组(在堆中分配内存空间,通过new delete管理内存) 使用包涵头文件#include <vector> vector<ElmentTpye> ...
- c++ const修饰词
常变量: const 类型说明符 变量名 // const int i = 20;常变量定义必需初始化赋值且变量值不可更改 常引用: const 类型说明符 &引用名 //引用:指 ...