Skip to content

Latest commit

 

History

History
166 lines (108 loc) · 4.69 KB

90-视图集.md

File metadata and controls

166 lines (108 loc) · 4.69 KB

通过前几章的折腾,我们已经把文章增删改查都完成了。经过合理运用类和继承的理念,代码已经相当精简了。但是, DRF 框架提供了更高层的抽象,可以让代码量进一步的减少。

来看看视图集的威力吧。

重构代码

大部分对接口的操作,都是在增删改查的基础上衍生出来的。既然这样,视图集就将这些通用操作集成在一起了。

试下用视图集重构代码。

首先将之前写的与文章有关的序列化器都注释掉,新增一个提供给视图集的新序列化器:

# article/serializers.py

...

class ArticleSerializer(serializers.HyperlinkedModelSerializer):
    author = UserDescSerializer(read_only=True)

    class Meta:
        model = Article
        fields = '__all__'

...

序列化器继承的 HyperlinkedModelSerializer 基本上与之前用的 ModelSerializer 差不多,区别是它自动提供了外键字段的超链接,并且默认不包含模型对象的 id 字段。

接着把之前写的文章视图也全注释掉,并新增代码:

# article/views.py

...

from rest_framework import viewsets
from article.serializers import ArticleSerializer

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    permission_classes = [IsAdminUserOrReadOnly]

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

视图集类把前面章节写的列表、详情等逻辑都集成到一起,并且提供了默认的增删改查的实现。

这些基础逻辑都在父类 ModelViewSet 里封装实现了,有兴趣可耐心研究源码。

perform_create() 跟之前一样,在创建文章前,提供了视图集无法自行推断的用户外键字段。

由于使用了视图集,我们甚至连路由都不用自己设计了,使用框架提供的 Router 类就可以自动处理视图和 url 的连接。

修改项目根路由

# drf_vue_blog/urls.py

...

from rest_framework.routers import DefaultRouter
from article import views

router = DefaultRouter()
router.register(r'article', views.ArticleViewSet)

urlpatterns = [
    ...
    
    # drf 自动注册路由
    path('api/', include(router.urls)),

    # article/urls.py 可以全注释掉,不需要了
    # path('api/article/', include('article.urls', namespace='article')),

]

最后为了让分页更准确,给模型类规定好查询排序:

# article/models.py

...

# 已经有的博客文章 model
class Article(models.Model):
    ...

    class Meta:
        ordering = ['-created']

完成了。

平复下心情,烧两柱香,抱着试一试的心态打开命令行:(或浏览器)

C:\...> http http://127.0.0.1:8000/api/
            
HTTP/1.1 200 OK
...

{
    "article": "http://127.0.0.1:8000/api/article/"
}

Router 类送给我们一个接口导航!

顺着导航里给的链接再试试:

C:\...> http http://127.0.0.1:8000/api/article/
            
HTTP/1.1 200 OK
...

{
    "count": 5,
    "next": "http://127.0.0.1:8000/api/article/?page=2",
    "previous": null,
    "results": [
        {
            ...
        },
        ...
    ]
}

正确的显示了列表。再顺着列表提供的详情页点进去也肯定是没问题的。权限控制也与之前的完全一样。

就这么几行代码,就完成了一整套的接口操作!

鱼和熊掌

视图集最大程度地减少需要编写的代码量,并允许你专注于 API 提供的交互和表示形式,而不是 URL 的细节。但并不意味着用它总是比构建单独的视图更好。

原因就是它的抽象程度太高了。如果你对 DRF 框架的理解不深并且需要做某种定制化业务,可能让你一时间无从下手。

精简可读之间,你应该根据实际情况进行取舍。

附加题

前几章用普通视图分别实现了列表和详情接口,并且不同的接口对应了不同的序列化器。

虽然视图集默认只提供一个序列化器,但是通过覆写 get_serializer_class() 方法可以根据条件而访问不同的序列化器:

class ArticleViewSet(viewsets.ModelViewSet):
    ...

    def get_serializer_class(self):
        if self.action == 'list':
            return SomeSerializer
        else:
            return AnotherSerializer

教程这里就暂时不去覆写了,后面有需要再来修改。

看到这里恭喜你,你已经把 DRF 基础的功能都体验完了,官方提供的入门教程也学完了。接下来的章节就是继续完善各类接口,并且熟悉框架提供的各类细节功能了。