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。
下面我们还是通过案例,为大家演示吧!
首先,先创建一个子应用。
python3manage.pystartappcollect
5.在collect下新建序列化器类
#collect下的serializers.py文件 fromstudents.modelsimportStudent fromrest_frameworkimportserializers classStudentModelSerializer(serializers.ModelSerializer): classMeta: model=Student fields=["id","name","age","sex"] extra_kwargs={ "name":{"max_length":10,"min_length":4}, "age":{"max_value":150,"min_value":0}, } defvalidate_name(self,data): ifdata=="root": raiseserializers.ValidationError("用户名不能为root!") returndata defvalidate(self,attrs): name=attrs.get('name') age=attrs.get('age') ifname=="alex"andage==22: raiseserializers.ValidationError("alex在22时的故事。。。") returnattrs classStudentInfoModelSerializer(serializers.ModelSerializer): classMeta: model=Student fields=["id","name"]
6.collect下的urls.py
fromdjango.urlsimportpath,re_path fromcollectimportviews 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\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 \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 \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 \d+)/$",views.Student9ModelViewSet.as_view({"get":"retrieve"})), ] """ 有了视图集以后,视图文件中多个视图类可以合并成一个,但是,路由的代码就变得复杂了, 需要我们经常在as_view方法,编写http请求和视图方法的对应关系, 事实上,在路由中,DRF也提供了一个路由类给我们对路由的代码进行简写。 当然,这个路由类仅针对于视图集才可以使用。 """ #路由类默认只会给视图集中的基本5个API生成地址[获取一条,获取多条,添加.删除,修改数据] fromrest_framework.routersimportDefaultRouter #实例化路由类 router=DefaultRouter() #router.register("访问地址前缀","视图集类","访问别名") #注册视图视图集类 router.register("student7",views.Student7ModelViewSet) #把路由列表注册到django项目中 urlpatterns+=router.urls
7.collect下的views.py
"""ViewSet视图集,继承于APIView,所以APIView有的功能,它都有,APIView没有的功能,它也没有""" fromrest_framework.viewsetsimportViewSet fromstudents.modelsimportStudent from.serializersimportStudentModelSerializer fromrest_framework.responseimportResponse classStudent1ViewSet(ViewSet): defget_5(self,request): student_list=Student.objects.all()[:5] serializer=StudentModelSerializer(instance=student_list,many=True) returnResponse(serializer.data) defget_one(self,request,pk): student=Student.objects.get(pk=pk) serializer=StudentModelSerializer(instance=student) returnResponse(serializer.data) defget_5_girl(self,request): student_list=Student.objects.filter(sex=False)[:5] serializer=StudentModelSerializer(instance=student_list,many=True) returnResponse(serializer.data) """如果希望在视图集中调用GenericAPIView的功能,则可以采用下面方式""" fromrest_framework.genericsimportGenericAPIView classStudent2ViewSet(ViewSet,GenericAPIView): queryset=Student.objects.all() serializer_class=StudentModelSerializer defget_5(self,request): student_list=self.get_queryset()[:5] serializer=StudentModelSerializer(instance=student_list,many=True) returnResponse(serializer.data) defget_one(self,request,pk): student=self.get_object() serializer=StudentModelSerializer(instance=student) returnResponse(serializer.data) defget_5_girl(self,request): student_list=self.get_queryset().filter(sex=False)[:5] serializer=StudentModelSerializer(instance=student_list,many=True) returnResponse(serializer.data) """ 上面的方式,虽然实现视图集中调用GenericAPIView,但是我们要多了一些类的继承。 所以我们可以直接继承GenericViewSet """ fromrest_framework.viewsetsimportGenericViewSet classStudent3GenericViewSet(GenericViewSet): serializer_class=StudentModelSerializer queryset=Student.objects.all() defget_5(self,request): student_list=self.get_queryset()[:5] serializer=self.get_serializer(instance=student_list,many=True) returnResponse(serializer.data) defget_5_girl(self,request): student_list=self.get_queryset().filter(sex=False)[:5] serializer=self.get_serializer(instance=student_list,many=True) returnResponse(serializer.data) """ 在使用GenericViewSet时,虽然已经提供了基本调用数据集(queryset)和序列化器属性,但是我们要编写一些基本的 API时,还是需要调用DRF提供的模型扩展类[Mixins] """ fromrest_framework.viewsetsimportGenericViewSet fromrest_framework.mixinsimportListModelMixin,CreateModelMixin classStudent4GenericViewSet(GenericViewSet,ListModelMixin,CreateModelMixin): queryset=Student.objects.all() serializer_class=StudentModelSerializer fromrest_framework.viewsetsimportModelViewSet classStudent5ModelViewSet(ModelViewSet): queryset=Student.objects.all() serializer_class=StudentModelSerializer #只读模型视图集 fromrest_framework.viewsetsimportReadOnlyModelViewSet classStudent6ReadOnlyModelViewSet(ReadOnlyModelViewSet): queryset=Student.objects.all() serializer_class=StudentModelSerializer #路由的使用 fromrest_framework.decoratorsimportaction classStudent7ModelViewSet(ModelViewSet): queryset=Student.objects.all() serializer_class=StudentModelSerializer #methods指定允许哪些http请求访问当前视图方法 #detail指定生成的路由地址中是否要夹带pk值,True为需要 @action(methods=["GET"],detail=False) defget_6(self,request): serilizer=self.get_serializer(instance=self.get_queryset().get(pk=6)) returnResponse(serilizer.data) """在多个视图类合并成一个视图类以后,那么有时候会出现一个类中需要调用多个序列化器""" """1.在视图类中调用多个序列化器""" """原来的视图类中基本上一个视图类只会调用一个序列化器,当然也有可能要调用多个序列化器""" from.serializersimportStudentInfoModelSerializer classStudent8GenericAPIView(GenericAPIView): queryset=Student.objects.all() #GenericAPI内部调用序列化器的方法,我们可以重写这个方法来实现根据不同的需求来调用不同的序列化器 defget_serializer_class(self): ifself.request.method=="GET": #2个字段 returnStudentInfoModelSerializer returnStudentModelSerializer defget(self,request): """获取所有数据的id和name""" student_list=self.get_queryset() serializer=self.get_serializer(instance=student_list,many=True) returnResponse(serializer.data) defpost(self,request): """添加数据""" data=request.data serializer=self.get_serializer(data=data) serializer.is_valid(raise_exception=True) serializer.save() returnResponse(serializer.data) """2.在一个视图集中调用多个序列化器""" classStudent9ModelViewSet(ModelViewSet): queryset=Student.objects.all() """要求: 列表数据list,返回2个字段, 详情数据retrieve,返回所有字段, """ defget_serializer_class(self): #本次客户端请求的视图方法名self.action ifself.action=="list": returnStudentInfoModelSerializer returnStudentModelSerializer
二.扩展功能
为了方便接下来的学习,我们创建一个新的子应用opt
python3manage.pystartappopt
因为接下来的功能中需要使用到登录功能,所以我们使用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
fromdjango.urlsimportpath fromoptimportviews urlpatterns=[ path('auth1/',views.Demo1APIView.as_view()), path('auth2/',views.Demo2APIView.as_view()), ]
opt下的views.py
fromrest_framework.viewsimportAPIView fromrest_framework.responseimportResponse fromrest_framework.permissionsimportIsAuthenticated,IsAdminUser """用户的认证和权限识别""" classDemo1APIView(APIView): """只允许登录后的用户访问""" permission_classes=[IsAuthenticated] defget(self,request): """个人中心""" returnResponse("个人中心") classDemo2APIView(APIView): """只允许管理员访问""" permission_classes=[IsAdminUser] defget(self,request): """个人中心2""" returnResponse("个人中心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
#自定义权限 fromrest_framework.permissionsimportBasePermission classMyPermission(BasePermission): defhas_permission(self,request,view): """ 针对访问视图进行权限判断 :paramrequest:本次操作的http请求对象 :paramview:本次访问路由对应的视图对象 :return: """ ifrequest.user.username=="xiaoming": returnTrue returnFalse classDemo3APIView(APIView): permission_classes=[MyPermission] defget(self,request): """个人中心3""" returnResponse("个人中心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
#限流 fromrest_framework.throttlingimportUserRateThrottle,AnonRateThrottle classDemo4APIView(APIView): #throttle_classes=[UserRateThrottle,AnonRateThrottle]#全局配置后,这里就不用指定 defget(self,request): """投票页面""" returnResponse("投票页面")
4.过滤Filtering
对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。
pip3installdjango-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
#过滤 fromrest_framework.genericsimportGenericAPIView,ListAPIView fromstudents.modelsimportStudent from.serializersimportStudentModelSerializer fromdjango_filters.rest_frameworkimportDjangoFilterBackend classDemo5APIView(ListAPIView): queryset=Student.objects.all() serializer_class=StudentModelSerializer filter_backends=[DjangoFilterBackend]#全局配置后,这里就不用指定了。 filter_fields=['age',"id"]#声明过滤字段
5.排序Ordering
对于列表数据,RESTframework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。
使用方法:
在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter过滤器,RESTframework会在请求的查询字符串参数中检查是否包含了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
#排序 fromrest_framework.filtersimportOrderingFilter classDemo6APIView(ListAPIView): queryset=Student.objects.all() serializer_class=StudentModelSerializer filter_backends=[DjangoFilterBackend,OrderingFilter]#局部配置会覆盖全局配置 filter_fields=['id',"sex"] ordering_fields=['id',"age"]
6.分页Pagination
RESTframework提供了分页的支持。
我们可以在配置文件中设置全局的分页方式,如:
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
#分页 fromrest_framework.paginationimportPageNumberPagination,LimitOffsetPagination """1.自定义分页器,定制分页的相关配置""" """ #页码分页PageNumberPagination 前端访问形式:GEThttp://127.0.0.1:8000/opt/data7/?page=4 page=1limit0,10 page=2limit10,20 #偏移量分页LimitOffsetPagination 前端访问形式:GEThttp://127.0.0.1:8000/opt/data7/?start=4&size=3 start=0limit0,10 start=10limit10,10 start=20limit20,10 """ classStandardPageNumberPagination(PageNumberPagination): """分页相关配置""" page_query_param="page"#设置分页页码关键字名 page_size=3#设置每页显示数据条数 page_size_query_param="size"#设置指定每页大小的关键字名 max_page_size=5#设置每页显示最大值 classStandardLimitOffsetPagination(LimitOffsetPagination): default_limit=2#默认限制,默认值与PAGE_SIZE设置一致 limit_query_param="size"#limit参数名 offset_query_param="start"#offset参数名 max_limit=5#最大limit限制 classDemo7APIView(ListAPIView): queryset=Student.objects.all() serializer_class=StudentModelSerializer #分页 #页码分页类 pagination_class=StandardPageNumberPagination #偏移量分页类 #pagination_class=StandardLimitOffsetPagination
注意:如果在视图内关闭分页功能,只需在视图内设置
pagination_class=None
到此这篇关于DjangoDRF路由与扩展功能的实现的文章就介绍到这了,更多相关DjangoDRF路由与扩展内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!