DRF--重写views(二)

简介: DRF--重写views

第三版


from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from djangoDemo.models import Book  # 导入表
from .serializers import BookSerializer
class GenericAPIView(APIView):  # 通用的API视图
    queryset = None
    serializer_class = None
    def get_queryset(self):
        # 这里要加.all() 虽然下面的ORM查询出来的是所有的数据
        # 但是由于DRF的内部机制,这里如果不加就会报错
        return self.queryset.all()
    def get_serializer(self, *args, **kwargs):
        # 不同请求的序列化器里传的参数是不一样的
        return self.serializer_class(*args, **kwargs)
class ListModelMixin(object):  # get方法,查询所有数据
    def list(self, request):
        queryset = self.get_queryset()
        ser_obj = self.get_serializer(queryset, many=True)
        return Response(ser_obj.data)
class CreateModelMixin(object):  # post方法
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)
class RetrieveModelMixin(object):  # get方法,查询单条数据
    def retrieve(self, request, id):
        # 先查询出所有,在过滤,在取第一个
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(book_obj)
        return Response(ser_obj.data)
class UpdateModelMixin(object):  # put方法
    def update(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(instance=book_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)  # 返回数据,注意不是ser_obj.validated_data
        return Response(ser_obj.errors)
class DestroyModelMixin(object):  # delete方法
    def destoy(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        if not book_obj:
            return Response('删除的对象不存在')
        book_obj.delete()
        return Response('Success')
class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    pass
class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    pass
class BookView(ListCreateAPIView):  # 查询所有数据和添加数据的方法
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    def get(self, request):
        return self.list(request)  # 调用get方法
    def post(self, request):
        return self.create(request)  # 调用post方法
class BookEditView(RetrieveUpdateDestroyAPIView):  # 查询单条数据和put、delete方法
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    def get(self, request, id):
        return self.retrieve(request, id)
    def put(self, request, id):
        return self.update(request, id)
    def delete(self, request, id):
        return self.destoy(request, id)


第四版


上面有两个get方法,一个是查询一条,一个是查询多条。那我们可不可以通过路由传参的方式来解决呢?只让它走一个,路由类似于这样

urlpatterns = [
    # url(r'^book/$', BookView.as_view()),
    # url(r'^book/(?P<id>\d+)', BookEditView.as_view()),
    url(r'^book/$', BookView.as_view({"get": "list", "post": "create"})),
    url(r'^book/(?P<id>\d+)', BookEditView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]

我们知道在CBV中,在执行视图函数时会先执行dispatch方法,我们继承了APIView,来看看源码是怎样写的,APIView里的as_view方法代码如下

View Code

这里可以看到可以传参,在去看看父类的as_view方法(第十七行)

View Code

很显然,从源代码里可以看出,父类的as_view也可以接收字典类型的传参,但是,如果key在initkwargs里,就会抛出一个错误(第七行),所以我们传参肯定会报错的,既然这样,那我们可以重写as_view方法,DRF已经替我们想好了,也替我们封装了,我们只需要使用就可以了,导入

from rest_framework.viewsets import ViewSetMixin

可以点进入看91到93行的源码

for method, action in actions.items():
    handler = getattr(self, action)
    setattr(self, method, handler)

这里,action 就是我们传来的参数,for循环之后,method就是原来的get请求,action就是我们写的list方法({"get":"list"})。然后通过setattr,执行get时,就会去执行我们写的list方法。

我们可以写个ModelViewSet类,来继承我们的两个get方法

class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
    pass

然后再写个类,让它继承这个类

class BookModelView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

在来改写路由

from django.conf.urls import url, include
from .views import  BookModelView
urlpatterns = [
    url(r'^book/$', BookModelView.as_view({"get": "list", "post": "create"})),
    url(r'^book/(?P<id>\d+)', BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]

这样我们所有的请求就都会去执行BookModelView视图了。


终极版


上面我们封装了那么多的类,其实DRF已经给我们封装好了,我们写的所有类都在下面的几个类里面,只是比我们自己写的全很多

from rest_framework import views
from rest_framework import viewsets
from rest_framework import generics
from rest_framework import mixins

我们进入viewsets里面看看最后的代码

class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    """
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.
    """
    pass

这里已经写好了,所以我们只需要继承ModelViewSet就可以了

只需要导入 from rest_framework import viewsets,继承就可以了,通过继承就可以看出,前面我们写了上百行的代码,只需要六行就实现了,这就上python的强大之处

from djangoDemo.models import Book  # 导入表
from .serializers import BookSerializer
from rest_framework import viewsets
class BookModelView(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

然后再改写路由

from django.conf.urls import url, include
from .views import  BookModelView
urlpatterns = [
    url(r'^book/$', BookModelView.as_view({"get": "list", "post": "create"})),
    url(r'^book/(?P<pk>\d+)', BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]

注意:路由分组命名那里要为pk,否则会报错

这样,简单的代码就实现了我们上面所有的代码


相关文章
|
6天前
|
开发框架 数据安全/隐私保护
flea-auth使用之功能子模块介绍
本篇介绍笔者 Flea框架下的 flea-auth模块中的 功能子模块
36 1
flea-auth使用之功能子模块介绍
|
9月前
|
Python
DRF--view
DRF--view
|
10月前
|
网络架构 Python
【Django学习】(十四)自定义action_router
【Django学习】(十四)自定义action_router
|
数据库 Python
Django ORM F对象和Q对象查询
F对象用于操作数据库中某一列的值,它可以在没有实际访问数据库获取数据值的情况下对字段的值进行引用 使用F对象之前需要将它引入当前的环境中:
121 0
Django ORM F对象和Q对象查询
|
缓存
Laravel-admin 重写源码 自定义排序回调
有几个业务相关的配置信息需要管理后台灵活配置,且返回的数据要进行排序 为了保证业务接口的请求速度,我们把这些配置信息接口做了缓存 在管理后台进行form表单提交的时候清空缓存,保证数据及时更新(比如删除、修改之后要刷新缓存) 测试阶段发现一个问题,laravel-admin 的 sortable 扩展和框架本身的form表单提交没有关系,执行排序的时候没有回调函数,导致排序操作后无法主动清除缓存。
305 0
Laravel-admin 重写源码 自定义排序回调
|
存储 缓存 NoSQL
【Django学习笔记 - 8】:session的配置和使用、类视图初使用
【Django学习笔记 - 8】:session的配置和使用、类视图初使用
306 0
【Django学习笔记 - 8】:session的配置和使用、类视图初使用
SAP Spartacus lazy load module 里包含了被其他 Component 静态引用的组件该怎么办
SAP Spartacus lazy load module 里包含了被其他 Component 静态引用的组件该怎么办
87 0
SAP Spartacus lazy load module 里包含了被其他 Component 静态引用的组件该怎么办
[重要!] SAP Spartacus加载网络请求的entity状态切换,统一在loader.reducer.ts里完成
[重要!] SAP Spartacus加载网络请求的entity状态切换,统一在loader.reducer.ts里完成
71 0
[重要!] SAP Spartacus加载网络请求的entity状态切换,统一在loader.reducer.ts里完成
|
Python
Django的rest_framework的视图之Mixin类编写视图源码解析
Django的rest_framework的视图之Mixin类编写视图源码解析 Mixin类编写视图 我们这里用auther表来做演示,先为auther和autherdetail写2个url 1 2 url(r'^autherdetail/(?P\d+)', views.
1394 0