Django REST Framework API Guide 02
本节大纲
1、Generic Views
2、ViewSets
1、Generic Views
CBV的主要的一个优点就是极大的允许了对于代码的从用。自然,rest framework取其优势,提供了很多可以重构的视图。rest framework 提供的 Generic Views可以让你很快速的构建跟数据库模型映射紧密的API视图。
如果 generic view不满足你的API需求,很简单,你可以放弃它去使用正常的APIView类,或者将generic view内部包含的mixins和基础类重构成自己需要的,完成对于generic view的重用
样例
- class StudentListView(ListAPIView):
- queryset = Student.objects.all()
- serializer_class = StudentListSerializer
- ###########################################serilizers,单独建立一个serializers文件
- from rest_framework.serializers import ModelSerializer
- from app01.models import Student
- class StudentListSerializer(ModelSerializer):
- class Meta:
- model = Student
- fields = ('name', 'age', 'gender', 'uuid')
- ###########################################url
- path('student/', StudentListView.as_view(), name='list-student'),
对于更复杂的需求,你可能需要重写各种各样的方法在你的视图类上,例如
- class StudentListView(ListAPIView):
- queryset = Student.objects.all()
- serializer_class = StudentListSerializer
- def list(self, request, *args, **kwargs):
- queryset = self.get_queryset()
- serializer = StudentListSerializer(queryset, many=True)
- return Response(serializer.data)
如上、我们重写了list方法,这是查看一下源码会发现这是ListAPIView的get方法调用的方法。
对于一些简单的例子,你可以通过as_view()方法传入各种属性,例如
- path('student/', StudentListView.as_view(queryset = Student.objects.all(), serializer_class = StudentListSerializer), name='list-student'),
API Reference
GenericAPIView继承并扩展了APIView类,添加了很多对于标准的列表跟详细视图的常用的行为,其中每一个具体的generic views都是由GenericAPIView和其他一个或者多个mixin类组合而成。
Attributes
Basic settings
下面的属性控制这基础视图的行为。
1、queryset
用来返回一个视图的对象。你必须设置这个属性,或者是重写get_queryset()方法。如果你在重写一个视图方法,调用get_queryset()比直接用这个属性更好,因为queryset会一次获取整体的范围,这些数据将被缓存给各个随后的请求
2、serializer_class
序列化的类,用来验证,反序列化输入和序列化输出。同样的可以设置这个属性,或者是重写get_serializer_class()方法
3、lookup_field
这个模型字段应该被用来给对象查找单独的模型实例,默认是pk,如果url上的匹配也是pk,视图会自动筛选出主键值等于pk值的单独模型实例。
4、lookup_url_kwarg
URL关键字参数,可以被用来查找对象,url设置里面用该包含一个关键字对应的值,如果没有设置,默认使用lookup_field.
Pagination
接下来的方法主要是和list view相关的分页。
1、pagination_class
用来对list结果进行分页。可以在setting里面配置用'rest_framework.pagination.PageNumberPagination'来配置一个'DEFAULT_PAGINATION_CLASS'参数
Filtering
1、filter_backends
有很多可用的filter backend类可以用来对queryset进行筛选。默认可以再settings文件中设置DEFAULT_FILTER_BACKENDS
Methods
Base methods
1、get_query(self)
返回一个可以被list视图使用的queryset,并且作为后面查询具体视图的基础,默认返回queryset由queryset属性控制
- def get_queryset(self):
- user = self.request.user
- return user.accounts.all()
2、get_object(self)
返回一个给具体视图(detail view)使用的对象实例。默认用lookup_field参数来筛选基础的queryset,可以被重写来提供更复杂的行为。
- def get_object(self):
- queryset = self.get_queryset()
- filter = {}
- for field in self.multiple_lookup_fields:
- filter[field] = self.kwargs[field]
- obj = get_object_or_404(queryset, **filter)
- self.check_object_permissions(self.request, obj)
- return obj
如果你的api没有权限认证,那可以直接丢弃掉最后一句self.check_object_permissions(self.request, obj)
3、filter_queryset
传入一个queryset,通过在使用的filter backends来筛选它,返回一个新的queryset
- def filter_queryset(self, queryset):
- filter_backends = (CategoryFilter,)
- if 'geo_route' in self.request.query_params:
- filter_backends = (GeoRouteFilter, CategoryFilter)
- elif 'geo_point' in self.request.query_params:
- filter_backends = (GeoPointFilter, CategoryFilter)
- for backend in list(filter_backends):
- queryset = backend().filter_queryset(self.request, queryset, view=self)
- return queryset
4、get_serializer_class(self)
返回一个序列化的类,默认返回serializer_class属性也可以重写成动态行为
- def get_serializer_class(self):
- if self.request.user.is_staff:
- return FullAccountSerializer
- return BasicAccountSerializer
Save and deletion hooks(保存和删除的钩子)
下面这些方法是mixin类提供的,提供了对对象的保存和删除行为简易重写
.perform_create(self, serializer) ==> 当保存一个新的实例对象时由CreateModelMixin发起
.perform_update(self, serializer) ==> 当更新一个已有的实例对象时由UpdateModelmixin发起
.perform_destory(self, instance) ==> 当删除一个实例对象时由DestoryModelMixin发起
当你需要的数据在request里面,但是不是request.data的一部分的时候,这些钩子就会变得特别有用,
比如你想记录request.user到实例里面
- def perform_create(self, serializer):
- serializer.save(user=self.request.user)
比如你想在保存操作的同时发送一封邮件出去
- def perform_update(self, serializer):
- instance = serializer.save()
- send_email_confirmation(user=self.request.user, modified=instance)
比如利用这些钩子提供额外的验证在数据库存储数据之前,并可以引发ValidationError()
- def perform_create(self, serializer):
- queryset = SignupRequest.objects.filter(user=self.request.user)
- if queryset.exists():
- raise ValidationError('You have already signed up')
- serializer.save(user=self.request.user)
注意,这些方法代替了2.X版本里面的pre_save
, post_save
, pre_delete
和 post_delete方法,它们不再可用
在GenericAPIView里面,顺便跟下面的方法有个眼缘。。
- get_serializer_context(self) #返回一个字典包含任何额外的数据,需要添加到serializer里面的
- get_serializer(self, instance=None, data=None, many=False, partial=False) # 返回一个serializer实例
- get_paginated_response(self, data) # 返回一个分页格式的Response对象
- paginate_queryset(self, queryset) # 对有需求的queryset进行分页,返回一个page对象或者空None,如果没有配置
Mixins
mixin类提供了一些是用来提供基础视图行为的措施。注意是mixin类提供的行为方法,而不是自定义处理方法,比如.get()或者.post(). 它允许更加灵活的组合行为
导入
- rest_framework.mixins
ListModelMixin
提供.list(request, *args, **kwargs)方法,正常会返回200 ok的返回和序列化的queryset作为body,返回的数据可以被分页。
CreateModelMixin
提供了.create(request, *args, **kwargs)方法,正常返回201 created返回和序列化的对象作为body. 如果返回的数据不合法,返回400和错误的详细作为body
RetrieveModelMixin
提供.Retrieve(request, *args, **kwargs)方法,正常返回200 ok和创建好的序列化实例. 否则返回404 Not Found.
UpdateModelMixin
提供.update(request, *args, **kwargs)方法,更新现有的实例。也提供了.partial_update(request, *args, **kwargs)方法,跟update很像,除了所有的更新字段都是可选的。允许支持patch请求。正常返回200 ok返回,序列化的对象。否则400 bad request.
DestoryModelMixin
.destory(request, *args, **kwargs)方法,正常204 No Content返回,否则404 Not Found.
Concrete View Classes
CreateAPIView
只创建;支持post方法处理;扩展:GenericAPIView, CreateModelMixin
ListAPIView
只读,展示一组模型实例;支持get方法处理;扩展:GenericAPIView, ListModelMixin
RetrieveAPIView
只读,展示一个单独的模型实例,支持get方法处理;扩展:GenericAPIView, RetrieveModelMixin
DestoryAPIView
只删除,针对单独的模型实例. 支持put和patch方法处理;扩展:GenericAPIView, UpdateModelMixin
UpdateAPIView
只更新,针对单独模型实例. 支持put和patch方法处理;扩展:GenericAPIView, UpdateModelMixin
ListCreateAPIView
读写,展示一组模型实例. get和post方法处理;扩展:GenericAPIView,ListModelMIxin,CreateModelMixin
RetrieveUpdateAPIView
读或者更新,展示一个独立的模型实例. get, put和patch方法处理;扩展:GenericAPIView, RetrieveModelMixin,UpdateModelMixin
RetrieveDestoryAPIView
读或删除,展示一个独立的模型实例. get和delete方法处理;扩展:GenericAPIView,RetrieveModelMixin, DestoryModelMIxin
RetrieveUpdateDestoryAPIView
读或者删除,展示一个独立的模型实现. get和delete方法处理;扩展:GenericAPIView,RetrieveModelMixin,DestoryModelMixin
RetrieveUpdateDestoryAPIView
读写删除,展示一个独立的模型实例. get, put, patch和delete方法处理;扩展:GenericAPIView,RetrieveMinxin,UpdateModelMixin,DestoryModelMixin
Customizing the generic views
Creating custom mixins
比如,需要查找对象基于多个url字段,你可以创建一个mixin类如下:
- class MultipleFieldLookupMixin(object):
- """
- Apply this mixin to any view or viewset to get multiple field filtering
- based on a `lookup_fields` attribute, instead of the default single field filtering.
- """
- def get_object(self):
- queryset = self.get_queryset() # Get the base queryset
- queryset = self.filter_queryset(queryset) # Apply any filter backends
- filter = {}
- for field in self.lookup_fields:
- if self.kwargs[field]: # Ignore empty fields.
- filter[field] = self.kwargs[field]
- obj = get_object_or_404(queryset, **filter) # Lookup the object
- self.check_object_permissions(self.request, obj)
- return obj
你可以简单得将这个mixin应用在view或者viewset,当你想需要应用这个客制化行为的任何时候
- class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
- queryset = User.objects.all()
- serializer_class = UserSerializer
- lookup_fields = ('account', 'username')
Creating Custom Base Classes
如果你使用mixin链接多个视图,可以用下面的这种更进一步创建你自己的基础视图,贯穿你的项目
- class BaseRetrieveView(MultipleFieldLookupMixin,
- generics.RetrieveAPIView):
- pass
- class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin,
- generics.RetrieveUpdateDestroyAPIView):
- pass
Put As Create
3.0版本的rest framework mixins 对待put即是更新也是创建,主要依赖于你的项目是不是已经存在
2、ViewSets
首先需要记住的一点是viewset是一种简单的CBV,不提供任何处理方法比如.get()或者.post(),而是用.list()和.create()来替代,这种东西翻一下源码就知道了,当然熟悉了也就不需要特别记忆了。
还有一点值得注意的是相比于直接注册带有视图集在url设置里,使用路由类注册视图集将会是更好的选择,他将自动的为你决定url的设置,例如
- from rest_framework.generics import get_object_or_404
- from app01.serializers import PersonModelSerializer
- from rest_framework.viewsets import ModelViewSet, ViewSet
- from rest_framework.response import Response
- from app01.models import PersonResource
- class StudentViewSet(ViewSet):
- def list(self, request):
- queryset = PersonResource.objects.filter(job=1)
- serializer = PersonModelSerializer(queryset, many=True)
- return Response(serializer.data)
- def retrieve(self, request, pk=None):
- queryset = PersonResource.objects.filter(job=1)
- student = get_object_or_404(queryset, pk=pk)
- serializer = PersonModelSerializer(student)
- return Response(serializer.data)
如果需要的话,可以丙丁这个视图集到两个分开的视图,如下
- student_list = StudentViewSet.as_view({'get': 'list'})
- student_detail = StudentViewSet.as_view({'get': 'retrieve'})
但实际上不会这么做,而是注册一个路由绑定视图集来替代,这允许了url自动生成
- from rest_framework.routers import DefaultRouter
- from app01.customviewset import StudentViewSet
- router = DefaultRouter()
- router.register(r'student', StudentViewSet, base_name='student-viewset')
- urlpatterns = [
- ......
- ]
- urlpatterns += router.urls
此时就已经借助ViewSet完成了2类API
- http://127.0.0.1:8001/api/student/
- http://127.0.0.1:8001/api/student/1/
下面截图可以看到具体提供的URL格式,带format的就不说了,看了应该懂,只看对目前有用的就行
在使用viewset来完成此API工作的时候,可以发现还是有很多重复的变量申明的,对于追求极致的API来说显然是不允许的,所以接下来修改成ModelViewSet
- class StudentViewSet(ModelViewSet):
- queryset = PersonResource.objects.filter(job=1)
- serializer_class = PersonModelSerializer
其实这个定义跟上面讲的封装的高级视图很相似。
ViewSet Actions
- class UserViewSet(viewsets.ViewSet):
- """
- Example empty viewset demonstrating the standard
- actions that will be handled by a router class.
- If you're using format suffixes, make sure to also include
- the `format=None` keyword argument for each action.
- """
- def list(self, request):
- pass
- def create(self, request):
- pass
- def retrieve(self, request, pk=None):
- pass
- def update(self, request, pk=None):
- pass
- def partial_update(self, request, pk=None):
- pass
- def destroy(self, request, pk=None):
- pass
Introspecting ViewSet Actions
在dispatch的时候,下面的属性在视图集内是可用的
- basename - the base to use for the URL names that are created.
- action - the name of the current action (e.g., list, create).
- detail - boolean indicating if the current action is configured for a list or detail view.
- suffix - the display suffix for the viewset type - mirrors the detail attribute.
你可以注入下面的属性来调整当前操作的行为,比如限制权限
- def get_permissions(self):
- """
- Instantiates and returns the list of permissions that this view requires.
- """
- if self.action == 'list':
- permission_classes = [IsAuthenticated]
- else:
- permission_classes = [IsAdmin]
- return [permission() for permission in permission_classes]
Marking extra actions format routinng
如果你有特殊的方法应该是可路由的,你可以用@action装饰器来标记它们。与常规操作一样,额外的操作可以用于对象列表或单个实例。通过detail参数的True、False标示这个。通过DefaultRouter来配置action,包含pk在URL里面。
- class StudentViewSet(ModelViewSet):
- queryset = PersonResource.objects.filter(job=1)
- serializer_class = PersonModelSerializer
- @action(methods=['post'], detail=True)
- def change_age(self, request, pk=None):
- student = self.get_object()
- student.age += 1
- student.save()
- return Response({'status': '%s age changed.' % student.name})
- @action(detail=False)
- def ordering(self, request):
- student = PersonResource.objects.filter(job=1).order_by('modify_time')
- page = self.paginate_queryset(student)
- if page is not None:
- serializer = self.get_serializer(page, many=True)
- return self.get_paginated_response(serializer.data)
- serializer = self.get_serializer(student, many=True)
- return Response(serializer.data)
注意,我们一直使用的是DefaultRouter,而不是url里面自己定义。。当然上面的这种写法有点烦。。因为Detail=True的是只允许了post方法,可以改成get方法
可以随便打一个错误的url来看一下链接
id=1指向的是dandy,此时
也可以在装饰器里面添加额外的参数,这边就直接copy官方文档的了,随便看看
- @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])
- def set_password(self, request, pk=None):
- ...
装饰器默认是get请求们也可以自己添加
- @action(methods=['post', 'delete'], detail=True)
- def unset_password(self, request, pk=None):
- ...
Reversing action URLS
本身正常情况下,在django里面,我们通过url里面的name进行url反转,再特殊一点,如果遇到两个一样的name,会根据命名空间appname来进行区别。而如果使用了viewset视图集,可以抛弃.reverse()方法,使用再次封装的.reverse_action()进行url反转。
- @action(methods=['get', 'put'], detail=True)
- def change_age(self, request, pk=None):
- student = self.get_object()
- student.age += 1
- student.save()
- return Response({
- 'status': '%s age changed.' % student.name,
- 'url': self.reverse_action('change-age', args=[pk])
- })
注意 反转的basename其实就是action装饰器的函数名,尤其是当函数名跟上面的实例一样,有下划线_的时候,需要转换成-,别掉进坑。。
或者有一种更简单的方法
- @action(methods=['get', 'put'], detail=True)
- def change_age(self, request, pk=None):
- student = self.get_object()
- student.age += 1
- student.save()
- return Response({
- 'status': '%s age changed.' % student.name,
- 'url': self.reverse_action('change-age', args=[pk]),
- 'url1': self.reverse_action(self.change_age.url_name, args=[pk])
- })
API Reference
ViewSet
ViewSet继承了APIView,你可以使用APIView的提供的任何标准的属性,比如permission_classes
,authentication_classes...
视图集类不能提供任何执行操作,为了使用视图集类,你可以直白地重写类或者定义执行操作。
GenericViewSet
GenericViewSet继承自GenericAPIView,包含get_object(), get_queryset()方法和其他generic view基础行为,默认不包含操作。同样地,为了使用GenericViewSet类,你需要直白的重写类无论是mixin还是自定义执行操作。
ModelViewSet
继承自GenericAPIView,包含各种执行操作,源自各种各样的mixin类。
ModelViewSet提供:.list(), .retrieve(), .create(), .update(), .partial_update()和.destory()
因为是扩展了GenericAPIView,所以有很多属性可以使用,下面的几个示例都不是很重要,直接copy的官方文档
- class AccountViewSet(viewsets.ModelViewSet):
- """
- A simple ViewSet for viewing and editing accounts.
- """
- queryset = Account.objects.all()
- serializer_class = AccountSerializer
- permission_classes = [IsAccountAdminOrReadOnly]
或者同样的跟GenericAPIView的其他扩展类一样。
- class AccountViewSet(viewsets.ModelViewSet):
- """
- A simple ViewSet for viewing and editing the accounts
- associated with the user.
- """
- serializer_class = AccountSerializer
- permission_classes = [IsAccountAdminOrReadOnly]
- def get_queryset(self):
- return self.request.user.accounts.all()
ReadOnlyModelViewSet
继承自GenericAPIView,但是从名字就可以猜到read-only,所以支持.list(), .retrieve()方法
- class AccountViewSet(viewsets.ReadOnlyModelViewSet):
- """
- A simple ViewSet for viewing accounts.
- """
- queryset = Account.objects.all()
- serializer_class = AccountSerializer
Custome ViewSet base classes
有时你需要提供客制化的视图集类,而ModelViewSet并没有满足,就需要自定制。
- from rest_framework import mixins
- class CreateListRetrieveViewSet(mixins.CreateModelMixin,
- mixins.ListModelMixin,
- mixins.RetrieveModelMixin,
- viewsets.GenericViewSet):
- """
- A viewset that provides `retrieve`, `create`, and `list` actions.
- To use it, override the class and set the `.queryset` and
- `.serializer_class` attributes.
- """
- pass
这里,我们讲GenericView跟ViewSet放在了一起,因为这其中有很多很多相似的地方,如果每一个都看示例,翻源码就很好理解了,如果只是一笔看过,可能会混淆掉其中的内容,当然,如果真正做到看rest framework这一块,相信在这个领域已经不算是小白了,源码随便看看应该是可以的。
Django REST Framework API Guide 02的更多相关文章
- Django REST Framework API Guide 01
之前按照REST Framework官方文档提供的简介写了一系列的简单的介绍博客,说白了就是翻译了一下简介,而且翻译的很烂.到真正的生产时,就会发现很鸡肋,连熟悉大概知道rest framework都 ...
- Django REST Framework API Guide 03
本节大纲 1.Routers 2.Parsers 3.Renderers Routers Usage from rest_framework import routers router = route ...
- Django REST Framework API Guide 08
1.Filtering 2.Pagination FIltering GenericAPIView的子类筛选queryset的简单方法是重写.get_quueryset()方法. 1.根据当前用户进行 ...
- Django REST Framework API Guide 06
本节大纲 1.Validators 2.Authentication Validators 在REST框架中处理验证的大多数时间,您将仅仅依赖于缺省字段验证,或在序列化器或字段类上编写显式验证方法.但 ...
- Django REST Framework API Guide 04
本节大纲 1.serializers 1.Serializers Serializers允许复杂的数据,像queryset和模型实例转换成源生的Python数据类型.从而可以更简单的被渲染成JSON, ...
- Django REST Framework API Guide 07
本节大纲 1.Permissions 2.Throttling Permissions 权限是用来授权或者拒绝用户访问API的不同部分的不同的类的.基础的权限划分 1.IsAuthenticated ...
- Django REST Framework API Guide 05
本节大纲 1.Serializer fields 2.Serializer relations Serializer fields 1.serializer 字段定义在fields.py文件内 2.导 ...
- Django Rest Framework API指南
Django Rest Framework API指南 Django Rest Framework 所有API如下: Request 请求 Response 响应 View 视图 Generic vi ...
- tastypie Django REST framework API [Hello JSON]
tastypie is a good thing. Haven't test it thoroughly. Gonna need some provement. Now I will introduc ...
随机推荐
- 关于Java中扫描仪next()与nextLine()的区别
首先,next()一定要读取到有效字符后才可以结束输入,对输入有效字符之前遇到的空格键.Tab键或Enter键等结束符,next()方法会自动将其去掉,只有在输入有效字符之后,next()方法才将其后 ...
- MySQL事务,事务隔离级别详解
1.什么是事务 指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行. 2.事务的4个特性 原子性(Atomicity).一致性(Consistency).隔离性(Isolatio ...
- Html的简单学习笔记
1.Html简介 1)什么是html: HyperText Markup Language:超文本标记语言,网页语言. >超文本:超出文本范围. >标记: html中所有的操作都是使用标记 ...
- PHP-FIG - PHP 标准规范
转自:https://psr.phphub.org/ PHP 标准规范 PSR 是 PHP Standard Recommendations 的简写,由 PHP FIG 组织制定的 PHP 规范,是 ...
- centos7下安装pip以及mysql等软件
1.安装pip 安装失败了的提示: No package pip available.Error: Nothing to do 解决方法: 需要先安装扩展源EPEL. EPEL(http://fedo ...
- 2Servlet笔记
1.静态页面(html) 2.动态 用户可以输入数据,和页面交互. 3 BS和CS的区别 BS :Browser Server(WEB 服务器) CS : Client(qq tcp/ip协议) ...
- docker swarm 简易版
节点名称 相关服务 ip地址 master1/node1 swarm manager(master) / consul 192.168.132.131 master2/node2 swarm mana ...
- IIS 为应用程序池提供服务的进程在与 Windows Process Activation Service 通信时出现严重错误的解决方法
系统环境:Windows Server 2008 R2 64位, IIS 7.0 错误信息: 为应用程序池提供服务的进程在与 Windows Process Activation Service 通信 ...
- ipython介绍及使用
1. IPython介绍 ipython是一个python的交互式shell,比默认的python shell好用得多,支持变量自动补全,自动缩进,支持bash shell命令,内置了许多很有用的功能 ...
- Part-Four
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.