[Python自学] DRF (2) (视图类的封装)

参考博客:https://www.cnblogs.com/yuanchenqi/articles/8719520.html

一、mixins模块(level-1)

1.需要解决的问题

在 [Python自学] restframework 中,我们实现了publish和book的增删改查(包括单条查询,一共5个视图操作)。

但是如果我们还有很多同样需要实现5种操作的实例种类,那么代码重复量会非常大。如何解决这个问题,restframework已经为我们提供了解决方法。

2.mixins模块

restframework为我们提供了mixins模块:

from rest_framwork import mixins

mixins模块中为我们提供了5个类:

mixins.ListModelMixin  # 获取全量数据(对应get)
mixins.CreateModelMixin  # 插入数据(对应post)
mixins.UpdateModelMixin  # 更新数据(对应put)
mixins.DestroyModelMixin  # 删除数据(对应delete)
mixins.RetrieveModelMixin  # 获取单条数据(对应get)

3.authors对应的两个视图类

from rest_framework import mixins
from rest_framework import generics


class AuthorView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
    pass


class AuthorDetailView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,
                     generics.GenericAPIView):
    pass

AuthorView中主要做全量获取和创建一条数据,所以继承ListModelMixin和CreateModelMixin。

GenericAPIView继承自APIView,是使用Mixins的基础。

例如,在AuthorView中,他继承了ListModelMixin类,则相当于自己有了一个叫list的方法(这个list方法就相当于get视图方法),继承了CreateModelMixin类,相当于自己有了一个create的方法(相当于post视图方法),继承了GnericAPIView相当于继承了APIView类。

Authors对应的urls路由条目:

from django.contrib import admin
from django.urls import path, re_path
from demo import views

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('^publishes/$', views.PublishView.as_view(), name="publish"),
    re_path('^publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(), name="publishdetail"),
    re_path('^books/$', views.BookView.as_view(), name="book"),
    re_path('^books/(?P<pk>\d+)/$', views.BookDetailView.as_view(), name="bookdetail"),
    re_path('^authors/$', views.AuthorView.as_view(), name="author"),
    re_path('^authors/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(), name="authordetail"),
]

4.实现AuthorView类

from rest_framework import mixins
from rest_framework import generics
from .models import Author


# Author序列化类
class AuthorModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = "__all__"


class AuthorView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

    # 获取全部authors
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    # 插入一条数据
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

5.实现AuthorDetailView类

class AuthorDetailView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,
                       generics.GenericAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

    # 获取单条author记录
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    # 更新一条记录
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    # 删除一条记录
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

6.测试结果

获取全量数据:

Postman以get请求访问http://127.0.0.1:8000/authors/:

[
    {
        "id": 1,
        "name": "leo",
        "age": 32
    },
    {
        "id": 2,
        "name": "alex",
        "age": 35
    },
    {
        "id": 3,
        "name": "Jone",
        "age": 23
    },
    {
        "id": 4,
        "name": "Lucy",
        "age": 30
    }
]

插入一条数据:

Postman以post请求访问http://127.0.0.1:8000/authors/,post数据:

{
    "name": "李雷",
    "age": 90
}

成功返回以上数据,再查询全量数据:

[
    {
        "id": 1,
        "name": "leo",
        "age": 32
    },
    {
        "id": 2,
        "name": "alex",
        "age": 35
    },
    {
        "id": 3,
        "name": "Jone",
        "age": 23
    },
    {
        "id": 4,
        "name": "Lucy",
        "age": 30
    },
    {
        "id": 5,
        "name": "李雷",
        "age": 90
    }
]

成功插入数据。

获取一条数据:

Postman发送get请求,http://127.0.0.1:8000/authors/4/:

返回数据:

{
    "id": 4,
    "name": "Lucy",
    "age": 30
}

修改一条数据:

将id为4的author的年龄修改为33,向http://127.0.0.1:8000/authors/4/发送put请求,数据如下:

{
    "name": "Lucy",
    "age": 33
}

成功返回以上数据,再次查询id为4的author的信息:

{
    "id": 4,
    "name": "Lucy",
    "age": 33
}

年龄修改成功。

删除一条数据:

删除id为4的数据,发送delete请求到http://127.0.0.1:8000/authors/4/。

返回空值。

查看全量数据:

[
    {
        "id": 1,
        "name": "leo",
        "age": 32
    },
    {
        "id": 2,
        "name": "alex",
        "age": 35
    },
    {
        "id": 3,
        "name": "Jone",
        "age": 23
    },
    {
        "id": 5,
        "name": "李雷",
        "age": 90
    }
]

成功删除id为4的数据。

 

二、generic模块(level-2)

除了第一节中使用的mixins模块,在generic模块中还对mixins的使用进行了封装,AuthorView和AuthorDetailView还可以变成如下形式:

1.generic中封装的类

# 单独封装
generics.ListAPIView
generics.CreateAPIView
generics.RetrieveAPIView
generics.UpdateAPIView
generics.DestroyAPIView

# 两个操作组合封装
generics.ListCreateAPIView
generics.RetrieveUpdateAPIView
generics.RetrieveDestroyAPIView

# 三个操作组合封装
generics.RetrieveUpdateDestroyAPIView

generic将我们可以在视图类中用要的方法全部封装在一起,我们只需要继承就可以了,get、post、put、delete等方法都被封装在其中了。

2.使用这些类

from rest_framework import generics
from .models import Author


# Author序列化类
class AuthorModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = "__all__"


class AuthorView(generics.ListCreateAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers


class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

如上述代码所示,代码变得更加简洁了。我们只需要控制数据源(queryset)以及显示格式(serializer_class)即可。

三、viewsets模块(level-3)

我们可以将AuthorView和AuthorDetailView合并成一个类,能够执行5种操作。

from .models import Author
from rest_framework import viewsets


# Author序列化类
class AuthorModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = "__all__"


class AuthorViewSet(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

对应urls路由条目修改为:

from django.contrib import admin
from django.urls import path, re_path
from demo import views

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('^publishes/$', views.PublishView.as_view(), name="publish"),
    re_path('^publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(), name="publishdetail"),
    re_path('^books/$', views.BookView.as_view(), name="book"),
    re_path('^books/(?P<pk>\d+)/$', views.BookDetailView.as_view(), name="bookdetail"),
    re_path('^authors/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="author"),
    re_path('^authors/(?P<pk>\d+)/$', views.AuthorViewSet.as_view(
        {"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"}), name="authordetail"),
]

还是两个url路由条目,但是指向的是同一个视图类,不同的是视图函数对应的成员方法不同,用字典参数进行映射。

这里最关键的就是as_view()方法的参数。

这里的as_view()是AuthorViewSet中的as_view(),该方法在 ViewSetMixin 类中实现的,该方法对参数进行了处理。

而前面的PublishView等类的as_view()是在APIView类中实现的,是没有对参数进行处理的。

 

(>‿◠)✌

 

posted @ 2020-01-26 16:17  风间悠香  阅读(297)  评论(0编辑  收藏  举报