DRF视图的详细用法

视图的用法

1.DRF中的request以及response

DRF中传入视图的request对象 不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。

DRF中传入视图的response对象 REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。

添加配置文件

REST_FRAMEWORK = {

'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类

'rest_framework.renderers.JSONRenderer', # json渲染器

'rest_framework.renderers.BrowsableAPIRenderer', # 浏览API渲染器

)

}

2.DRF中的视图的优势

首先我们来看不使用DRF,视图怎么实现

通用视图基类与扩展类,以简化视图的编写

# 处理admin站点的请求

class BooksAPIView(View):

# GET /books/

def get(self, request):

books = BookInfo.objects.all()

book_list = []

for book in books:

book_list.append({

'id': book.id,

'btitle': book.btitle,

'bread': book.bread,

'bcomment': book.bcomment,

'is_delete': book.is_delete,

# 注意此处要加上url才能访问到图片的地址

'image': book.image.url if book.image else '',

'bpub_date': book.bpub_date

})

return JsonResponse(book_list, safe=False)

                                                                                       代码块1

怎么样,是不是感觉很复杂。我们的DRF就可以帮我们处理其中的大部分代码而不用我们自己去处理!!!

重点来了,怎么实现呢?

首先我们得了解一下,当我们不去自己继承View类定义类视图时,DRF给哦们提供了几个继承自View类的丰富的类

1.基类:APIView

APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

APIViewView的不同之处在于:

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制

支持定义的属性:

  • authentication_classes 列表或元祖,身份认证类
  • permissoin_classes 列表或元祖,权限检查类
  • throttle_classes 列表或元祖,流量控制类

APIView中仍和普通的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。

class BookListView(APIView):

"""使用APIView实现“获取所有图书信息”接口"""


def get(self, request):

"""

获取所有图书信息

GET /books/

:param request: Request类型的对象

:return: JSON

"""

qs = BookInfo.objects.all() # 查询要序列化的模型数据

serializer = BookInfoSerializer(qs, many=True) # 准备序列化器:将模型数据转字典数据

return Response(serializer.data) # 响应序列化的结果

                                                                                  代码块2

 对比代码块1,发现确实工作量减少很多

2.基类:GenericAPIView

提供的关于序列化器使用的属性与方法

 具体实现例子:

class BookListView(GenericAPIView):

"""使用GenericAPIView实现“获取所有图书信息”接口"""


serializer_class = BookInfoSerializer # 指定序列化器

queryset = BookInfo.objects.all() # 指定查询集

def get(self, reqeust):

"""

获取所有图书信息

GET /books/

:param reqeust: Request类型的对象

:return: JSON

"""

qs = self.get_queryset() # 获取查询集

serializer = self.get_serializer(qs, many=True)# 创建序列化器对象

return Response(serializer.data) # 响应序列化后的数据

 我们发现这样做反而增加了两行代码,怎么说他优化了呢?别急,下边的GenericAPIView扩展类要大显身手了

3.配合GenericAPIView使用的几个扩展类

我们发现前边的两个父类还需要进行函数的定义去处理不同的请求,这样我们还得在函数里边实现查询集以及序列化器的指定,工作量仍然很大。怎么解决呢?

GenericAPIView的五个扩展类给我们提供了五个方法分别进行增删改查的不同操作,这样我们就不用写那么多函数啦!!

五个扩展类(为啥是5个?答:增删改查,查有两个)

搭配GenericAPIView使用

1.ListModelMixin: 提供list方法快速实现列表视图

2.CreateModelMixin: 提供create方法快速实现创建资源的视图

3.RetrieveModelMixin 提供retrieve方法,可以快速实现返回一个存在的数据对象(需要传入pk)

4.UpdateModelMixin 提供update方法,可以快速实现更新一个存在的数据对象。 提供partial_update方法,可以实现局部更新

5.DestroyModelMixin 提供destroy方法,可以快速实现删除一个存在的数据对象

一个例子:

class BookDetailView(mixins.RetrieveModelMixin, GenericAPIView):

"""使用GenericAPIView实现“获取单一图书信息”接口"""


serializer_class = BookInfoSerializer # 指定序列化器

queryset = BookInfo.objects.all() # 指定查询集


def get(self, request, pk):

"""

获取单一图书信息

GET /books/<pk>/

:param request: Request类型的对象

:return: JSON

"""

return self.retrieve(request)

 看到没有,函数里边只有一行代码了,简化了吧!明显看得出来,这个父类帮我们吧return之前的事情都做了

 GenericAPIView搭配扩展类的使用的优势就显示出来了

我想说的是:这里还能简化!!!

1.CreateAPIView(等价于GenericAPIView+CreateModelMixin) 提供 post 方法 继承自: GenericAPIView、CreateModelMixin

2.ListAPIView 提供 get 方法 继承自:GenericAPIView、ListModelMixin

3.RetrieveAPIView 提供 get 方法 继承自: GenericAPIView、RetrieveModelMixin

4.DestoryAPIView 提供 delete 方法 继承自:GenericAPIView、DestoryModelMixin

5.UpdateAPIView 提供 put 和 patch 方法 继承自:GenericAPIView、UpdateModelMixin

6.RetrieveUpdateAPIView 提供 get、put、patch方法 继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

7.RetrieveUpdateDestoryAPIView 提供 get、put、patch、delete方法 继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

所以代码中的mixins.RetrieveModelMixin, GenericAPIView可以写成RetrieveAPIView

4.视图集父类1:ViewSet

那么能否继续优化呢?答案:能!!!

前边的父类仍需要写很多函数,这些函数定义仍然增加我们的工作量

ViewSet:将几个操作放在一起(前边的方法都是分开实现的)

list() 提供一组数据

retrieve() 提供单个数据

create() 创建数据

update() 保存数据

destory() 删除数据

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

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

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

如:

class BookInfoViewSet(viewsets.ViewSet):

def list(self, request):

books = BookInfo.objects.all()

serializer = BookInfoSerializer(books, many=True)

return Response(serializer.data)

def retrieve(self, request, pk=None):

try:

books = BookInfo.objects.get(id=pk)

except BookInfo.DoesNotExist:

return Response(status=status.HTTP_404_NOT_FOUND)

serializer = BookInfoSerializer(books)

return Response(serializer.data)

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

如:

url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),

url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})

5.视图集父类2:GenericViewSet

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

class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):

queryset = BookInfo.objects.all()

serializer_class = BookInfoSerializer

 设置url:

url(r'^books/$', views.BookInfoViewSet.as_view({'get': 'list'})),

url(r'^books/(?P<pk>\d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'}))

6.视图集父类3:ModelViewSet

只需定义    

queryset = BookInfo.objects.all()    

serializer_class = BookInfoAllSerializer

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

class BookInfoViewSet(ModelViewSet):

queryset = BookInfo.objects.all()

serializer_class = BookInfoAllSerializer

7.视图集父类4:ReadOnlyModelViewSet

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

class BookInfoViewSet(ReadOnlyModelViewSet):

"""使用视图集实现返回列表和单一数据"""

# 指定序列化器

serializer_class = BookInfoSerializer

# 指定查询集

queryset = BookInfo.objects.all()


# detail为False 表示路径名格式应该为 books/latest/

@action(methods=['get'], detail=False)

def latest(self, request):

"""

自定义action: 返回最新的图书信息

GET /books/latest/

"""

# latest : 先将数据根据'id'倒叙,再取第0个

book = BookInfo.objects.latest('id')

serializer = self.get_serializer(book)

return Response(serializer.data)

8.路由router

当我们完成上述工作后,发现路由默认5个,加上自己配置的有很多路由,每自定义一个新的方法时就得配置路由。

DRF提供了路由:Routers

快速实现路由 Routers主要有两个: SimpleRouter           DefaultRouter

DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。

使用: register(prefix, viewset, base_name)

prefix 该视图集的路由前缀

viewset 视图集

base_name 路由名称的前缀

在路由文件中创建router对象,并注册视图集,最后把视图加到urlpatterns中 如:

# 给视图集定义路由

router = DefaultRouter()

router.register(r'books', views.BookInfoViewSet)

# 将DRF生成的路由信息,添加到urlpatterns

urlpatterns += router.urls

猜你喜欢

转载自blog.csdn.net/weixin_31449201/article/details/81109128