作者:HelloGitHub-追梦人物

一旦我们使用了视图集,并实现了 HTTP 请求对应的 action 方法(对应规则的说明见 使用视图集简化代码),将其在路由器中注册后,django-restframework 自动会自动为我们生成对应的 API 接口。

目前为止,我们只实现了 GET 请求对应的 action——list 方法,因此路由器只为我们生成了一个 API,这个 API 返回文章资源列表。GET 请求还可以用于获取单个资源,对应的 action 为 retrieve,因此,只要我们在视图集中实现 retrieve 方法的逻辑,就可以直接生成获取单篇文章资源的 API 接口。

贴心的是,django-rest-framework 已经帮我们把 retrieve 的逻辑在 mixins.RetrieveModelMixin 里写好了,直接混入视图集即可:

class PostViewSet(
mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
):
serializer_class = PostListSerializer
queryset = Post.objects.all()
permission_classes = [AllowAny]

现在,路由会自动增加一个 /posts/:pk/ 的 URL 模式,其中 pk 为文章的 id。访问此 API 接口可以获得指定文章 id 的资源。

实际上,实现各个 action 逻辑的混入类都非常简单,以 RetrieveModelMixin 为例,我们来看看它的源码:

class RetrieveModelMixin:
"""
Retrieve a model instance.
"""
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)

retrieve 方法首先调用 get_object 方法获取需序列化的对象。get_object 方法通常情况下依据以下两点来筛选出单个资源对象:

  1. get_queryset 方法(或者 queryset 属性,get_queryset 方法返回的值优先)返回的资源列表对象。
  2. lookup_field 属性指定的资源筛选字段(默认为 pk)。django-rest-framework 以该字段的值从 get_queryset 返回的资源列表中筛选出单个资源对象。lookup_field 字段的值将从请求的 URL 中捕获,所以你看到文章接口的 url 模式为 /posts/:pk/,假设将 lookup_field 指定为 title,则 url 模式为 /posts/:title/,此时将根据文章标题获取单篇文章资源。

文章详情 Serializer

现在,假设我们要获取 id 为 1 的文章资源,访问获取单篇文章资源的 API 接口 http://127.0.0.1:10000/api/posts/1/,得到如下的返回结果:

可以看到很多我们需要在详情页中展示的字段值并没有返回,比如文章正文(body)。原因是视图集中指定的文章序列化器为 PostListSerializer,这个序列化器被用于序列化文章列表。因为展示文章列表数据时,有些字段用不上,所以出于性能考虑,只序列化了部分字段。

显然,我们需要给文章详情写一个新的序列化器了:

from .models import Category, Post, Tag

class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = [
"id",
"name",
] class PostRetrieveSerializer(serializers.ModelSerializer):
category = CategorySerializer()
author = UserSerializer()
tags = TagSerializer(many=True) class Meta:
model = Post
fields = [
"id",
"title",
"body",
"created_time",
"modified_time",
"excerpt",
"views",
"category",
"author",
"tags",
]

详情序列化器和列表序列化器几乎一样,只是在 fields 中指定了更多需要序列化的字段。

同时注意,为了序列化文章的标签 tags,我们新增了一个 TagSerializer,由于文章可能有多个标签,因为 tags 是一个列表,要序列化一个列表资源,需要将序列化器参数 many 的值指定为 True

动态 Serializer

现在新的序列化器写好了,可是在哪里指定呢?视图集中 serializer_class 属性已经被指定为了 PostListSerializer,那 PostRetrieveSerializer 应该指定在哪呢?

类似于视图集类的 queryset 属性和 get_queryset 方法的关系, serializer_class 属性的值也可以通过 get_serializer_class 方法返回的值覆盖,因此我们可以根据不同的 action 动作来动态指定对应的序列化器。

那么如何在视图集中区分不同的 action 动作呢?视图集有一个 action 属性,专门用来记录当前请求对应的动作。对应关系如下:

HTTP 请求 对应 action 属性的值
GET list(资源列表)/ retrieve(单个资源)
PUT update
PATCH partial_update
DELETE destory

因此,我们在视图集中重写 get_serializer_class 方法,写入我们自己的逻辑,就可以根据不同请求,分别获取相应的序列化器了:

class PostViewSet(
mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
):
# ... 省略其他属性和方法
def get_serializer_class():
if self.action == 'list':
return PostListSerializer
elif self.action == 'retrieve':
return PostRetrieveSerializer
else:
return super().get_serializer_class()

后续对于其他动作,可以再加 elif 判断,不过如果动作变多了,就会有很多的 if 判断。更好的做好是,给视图集加一个属性,用于配置 action 和 serializer_class 的对应关系,通过查表法查找 action 应该使用的序列化器。

class PostDetailViewSet(viewsets.GenericViewSet):
# ... 省略其他属性和方法
serializer_class_table = {
'list': PostListSerializer,
'retrieve': PostRetrieveSerializer,
} def get_serializer_class():
return self.serializer_class_table.get(
self.action, super().get_serializer_class()
)

现在,再次访问单篇文章 API 接口,可以看到返回了更加详细的博客文章数据了:


关注公众号加入交流群

第 7 篇:文章详情的 API 接口的更多相关文章

  1. F5 api接口开发实战手册(二)

    F5 rest api 各对象使用方式详解 本篇文章介绍rest api接口下Collection.Resource.Subcollections.SubResource的各种使用方法.如果您不了解这 ...

  2. 各开放平台API接口通用SDK序列文章 前言

    最近两年一直在做API接口相关的工作,在平时工作中以及网上看到很多刚接触API接口调用的新人一开始会感到很不适应,要看的文档一大堆,自己要调用的接口找不着,或都找着了不知道怎么去调用,记得包括自己刚开 ...

  3. 怎样提供一个好的移动API接口服务/从零到一[开发篇]

    引语:现在互联网那么热,你手里没几个APP都不好意思跟别人打招呼!但是,难道APP就是全能的神吗?答案是否定的,除了优雅的APP前端展示,其实核心还是服务器端.数据的保存.查询.消息的推送,无不是在服 ...

  4. Restful风格API接口开发springMVC篇

    Restful风格的API是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件.它主要用于客户端和服务器交互类的软件.基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机 ...

  5. Expo大作战(三十一)--expo sdk api之Payments(expo中的支付),翻译这篇文章傻逼了,完全不符合国内用户,我只负责翻译大家可以略过!

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

  6. HelloDjango 第 08 篇:开发博客文章详情页

    作者:HelloGitHub-追梦人物 文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库 首页展示的是所有文章的列表,当用户看到感兴趣的文章时,他点击文章的标题或者继续阅读的按 ...

  7. thinkPHP中的文章详情页实现“上一篇下一篇”功能经验分享

    前段时间在公司中接触到了用thinkPHP搭建的项目,其中涉及到了文章详情页上一篇下一篇翻页的功能实现效果. 因为刚接触这套框架和PHP,所以整理一下实现该功能的经验方法. 如果有不到位的地方,欢迎指 ...

  8. 可能是把 Java 接口讲得最通俗的一篇文章

    读者春夏秋冬在抽象类的那篇文章中留言,"二哥,面试官最喜欢问的一个问题就是,'兄弟,说说抽象类和接口之间的区别?',啥时候讲讲接口呗!" 对于面向对象编程来说,抽象是一个极具魅力的 ...

  9. API接口通讯参数规范(2)

    针对[API接口通讯参数规范]这篇文章留下的几个问题进行探讨. 问题1 试想一下,如果一个http请求返回一个500给我们,那我们是不是都不用看详情都知道该次请求发生了什么?这正是一个标准的结果码意义 ...

随机推荐

  1. UVA-2【NOI2014】起床困难综合症

    #2. [NOI2014]起床困难综合症 21 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm 一直坚持与起床困难综合症作斗争.通过 ...

  2. [bzoj2088]P3505 [POI2010]TEL-Teleportation

    洛谷 bzoj 用了分层图的思想 题意 给一张图,要求你再尽可能的多连边,使得从1到2至少要经过5条边 没啥复杂的公式,讲解都在注释里 #include<cstdio> #include& ...

  3. swupdate 之 readback handler

    背景 使用 swupdate 作为 OTA 方案 ,有项目要求在写入数据到分区之后需要再次读出校验. 初步实现:readout-verify attribute 初步分析有两种方式 方案一 在每一笔数 ...

  4. VUE简单整理

    在用 Vue.js 构建大型应用时推荐使用 NPM 安装: # 最新稳定版 $ cnpm install vue 命令行工具 Vue.js 提供一个官方命令行工具,可用于快速搭建大型单页应用. # 全 ...

  5. 使用jQuery完成课工场论坛列表

    1.点击我要发帖 2.显示出form表单,然后我们填入标题和选择板块 3.点击发布,隐藏表单,发帖列表中出现随机头像,刚才填入的标题和板块显示在列表中,其中还显示出了发布消息的时间 4.再一次的点击我 ...

  6. S - Making the Grade POJ - 3666 结论 将严格递减转化成非严格的

    S - Making the Grade POJ - 3666 这个题目要求把一个给定的序列变成递增或者递减序列的最小代价. 这个是一个dp,对于这个dp的定义我觉得不是很好想,如果第一次碰到的话. ...

  7. OpenWrt R2020.3.11 去广告 抗污染 加速 PSW 无缝集成 UnPnP NAS

    近期更新:OpenWrt R2020.3.11版本2020.03.16编译. 按大家要求,新发布固件携带了编译时用到的全部软件包 加入了国内域名加速解析脚本 解决了原去广告,DNS优化方案与PSW冲突 ...

  8. Jmeter-Throughput Controller 吞吐量控制器

    比如在压测是时候,我设置了100个线程组,循环2次,那么我想根据吞吐量进行并发请求,这时候可以用到这个吞吐量控制器 PercentExecutions:按执行次数的百分比来计算执行次数,Through ...

  9. Python脚本:实现excel表格导入到数据库,支持mysql,postgresql,MongoDB

    import xlrd,re from datetime import datetime from xlrd import xldate_as_tuple # 判断上传表格是否与模板要求一致 def ...

  10. JS作用域和变量提升看这一篇就够了

    作用域是JS中一个很基础但是很重要的概念,面试中也经常出现,本文会详细深入的讲解这个概念及其他相关的概念,包括声明提升,块级作用域,作用域链及作用域链延长等问题. 什么是作用域 第一个问题就是我们要弄 ...