1
- 博客文章需要排版,否则难以凸显标题、正文、注释等内容之间的区别。作为博客写手来说,比较流行且好用的排版则是采用 Markdown 语法。
1
+ 博客文章需要排版,否则难以凸显标题、正文、注释等内容之间的区别。作为博客写手来说,比较流行且好用的排版是采用 Markdown 语法。
2
2
3
- > 如果你没听过什么是 Markdown , [ 这里 ] ( https://www.dusaiphoto.com/article/20/ ) 有一些简单介绍 。
3
+ 严格来说, Markdown 是一种排版标注规则。它将两个星号包裹的文字标注为重要文本(通常也就是粗体字),比如原始文本中的 ` **Money** ` ,在 Markdown 语法中应该被”渲染“为粗体,也就是 ** Money ** 。类似的还有斜体、代码块、表格、公式等注释,就请读者自行了解了 。
4
4
5
- 渲染 Markdown 可以在前端也可以在后端。本文将使用后端渲染 Markdown 语法的形式,以便你理解 DRF 框架的知识。
5
+ > [ 关于 Markdown] ( https://www.dusaiphoto.com/article/20/ ) 的简单介绍。
6
+
7
+ ”渲染“ Markdown 也就是把原始文本中的注释转化为前端中真正被用户看到的 HTML 排版文字。渲染过程可以在前端也可以在后端,本文将使用后端渲染,以便你理解 DRF 的相关知识。
6
8
7
9
## 模型和视图
8
10
9
- 为了将博文的正文部分渲染为 html 标签,首先给文章模型添加一个 ` get_md() ` 方法:
11
+ 为了将博文的 Markdown 正文渲染为 html 标签,首先给文章模型添加一个 ` get_md() ` 方法:
10
12
11
13
``` python
12
14
# article/models.py
@@ -31,9 +33,9 @@ class Article(models.Model):
31
33
return md_body, md.toc
32
34
```
33
35
34
- 方法返回了元组,包含了渲染为 html 的正文和目录 。
36
+ 方法返回了包含了两个元素的元组,分别为已渲染为 html 的 ** 正文 ** 和 ** 目录 ** 。
35
37
36
- 这些渲染后的数据,在文章详情接口是需要的,但是在列表接口却是毫无意义的 ,因此又要用到视图集根据请求方式动态获取序列化器的技术了:
38
+ 这些渲染后的数据,在文章 ** 详情接口 ** 是需要的,但是在 ** 列表接口 ** 却没太有必要 ,因此又要用到视图集根据请求方式动态获取序列化器的技术了:
37
39
38
40
``` python
39
41
# article/views.py
@@ -57,7 +59,7 @@ class ArticleViewSet(viewsets.ModelViewSet):
57
59
58
60
## 序列化器
59
61
60
- 因为** 文章列表接口** 和** 详情接口** 只有一点点返回字段的区别,其实大部分功能还是一样的。那么常年被面向对象编程熏陶的你 ,“把他抽象成父类!” 应该可以脱口而出:
62
+ 因为** 文章列表接口** 和** 详情接口** 只有一点点返回字段的区别,其实大部分功能还是一样的。那么被面向对象编程熏陶的你 ,“把他抽象成父类!” 应该可以脱口而出:
61
63
62
64
``` python
63
65
# article/serializers.py
@@ -89,7 +91,7 @@ class ArticleSerializer(ArticleBaseSerializer):
89
91
90
92
与 Django 表单类似,你可以继承扩展和重用序列化器。就像上面的代码一样,在父类上声明一组通用的字段或方法,然后在许多序列化程序中使用它们。
91
93
92
- 但是 ` Meta ` 内部类比较特殊 ,它不会隐式从父类继承。虽然有办法让它隐式继承,但这是不被推荐的,你应该显式声明它,以使得其行为更清晰 。
94
+ 但是内部类 ` class Meta` 比较特殊 ,它不会隐式从父类继承。虽然有办法让它隐式继承,但这是不被推荐的,你应该显式声明它,以使得序列化器的行为更清晰 。
93
95
94
96
另外,如果你觉得在列表接口连 ` body ` 字段也不需要显示的话,你可以传入 ` extra_kwargs ` 使其变成仅可写却不显示的字段。
95
97
@@ -100,6 +102,7 @@ class ArticleSerializer(ArticleBaseSerializer):
100
102
101
103
...
102
104
105
+ # 注意继承的父类是 ArticleBaseSerializer
103
106
class ArticleDetailSerializer (ArticleBaseSerializer ):
104
107
# 渲染后的正文
105
108
body_html = serializers.SerializerMethodField()
@@ -117,10 +120,12 @@ class ArticleDetailSerializer(ArticleBaseSerializer):
117
120
fields = ' __all__'
118
121
```
119
122
120
- ` body_html ` 、 ` toc_html ` 这两个渲染后的字段是经过加工后的数据,不存在于原始的数据中。为了将这类只读的附加字段添加到接口里,就可以用到 ` SerializerMethodField() ` 字段了。比如说 ` body_html ` 字段,它会自动去调用 ` get_body_html() ` 方法,并将其返回结果作为需要序列化的数据。方法中的 ` obj ` 参数是序列化器获取到的 model 实例,也就是文章对象了。
123
+ ` body_html ` 、 ` toc_html ` 这两个渲染后的字段是经过加工后的数据,不存在于原始的数据中。为了将这类只读的附加字段添加到接口里,就可以用到 ` SerializerMethodField() ` 字段了。比如说上面代码中的 ` body_html ` 字段,它会自动去调用 ` get_body_html() ` 方法,并将其返回结果作为需要序列化的数据。方法中的 ` obj ` 参数是序列化器获取到的 model 实例,也就是文章对象了。
121
124
122
125
这样就大功告成了,读者自己测试一下,顺利的话详情接口就可以返回 Markdown 渲染后的数据了。
123
126
127
+ > 记得原始文本应该用 Markdown 语法编写。成功的话 ` body_html ` 字段返回的是带有 html 标签的文本。
128
+ >
124
129
> 代码重构得太早可能会导致某些不必要的抽象,太晚又可能堆积太多”屎山“而无从下手。理想情况下的重构是随着项目的开发同时进行的,在合适的节点进行合适的抽象,看着代码逐渐规整,你也会相当有成就感。
125
130
126
131
另一个问题是,有时候你可能出于版权方面的考虑不愿意将原始的 Markdown 文章数据给任意用户,那么这里只要做一次鉴权,根据用户的权限选用不同的序列化器即可。(非管理员不返回原始文章数据)
0 commit comments