致虚极 守静笃
序列化器
2020-04-21发布 365

REST framework

我们继续之前的内容,让我们先进入项目文件夹react_drf,激活虚拟环境,并安装REST framework

$ source venv/bin/activate
// 激活后命令提示符前面会出现(venv)
(venv) $ pip install djangorestframework

Django REST framework is a powerful and flexible toolkit for building Web APIs.

官方介绍:Django REST framework是一个用于构建WEB API的强大而灵活的工具。

还记得在上一篇文章中提到的RESTful API吗?这次我们就来试试使用REST framework这个库来改造我们之前写的程序。

安装完成后,记得到项目文件夹backend/backend/settings.py文件中注册:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework', # 加上这个
    'article.apps.ArticleConfig',
]

扩展模型

打开我们的backend/article/models.py文件,原本的内容有点少,我们首先把这个模型扩展一下:

from django.db import models


class Article(models.Model):
    title = models.CharField(max_length=50)
    body = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ('-created',)

注意我们定义的继承了models.Model的类Article,与数据库中的有对应关系,可以看到这个类的不同属性分别是不同的对象示例,它们对应了数据库中的的不同,并且代表了不同的数据类型。

createdupdated通过将两个不同的参数设置为True实现了自动保存创建时间与最后修改时间的功能。

这里在元类里定义了以创建时间降序排序,注意ordering应该是一个元组,所以别忘了逗号,

好啦,还记得每次更改模型后要做什么?

(venv)  $ python manage.py makemigrations article 
Migrations for 'article':
  article/migrations/0001_initial.py
    - Create model Article
(venv)  $ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, article, auth, authtoken, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  ……
  Applying sessions.0001_initial... OK

现在迁移完成了,但是现在不急着去写视图和模板,我们要开始制作自己的RESTful API。

序列化

还记得之前提过,REST的意思是表现层状态转换,我们需要有一个工具来对模型进行序列化与反序列化,通俗的讲法序列化就是将语言中的对象转化为可以存储或传输的形式,反序列化就是反过来的过程。

在前后端分离模式的开发中,由于前后端语言往往是不同的,例如后端Java,前端JavaScript,或者有移动端的Kotlin,往往需要一种较为通用的格式,JSON就是一个不错的选择。

好了,开始行动吧,在article文件夹中新建一个serializers.py文件:

# article/serializers.py
class ArticleSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=True, max_length=50)
    body = serializers.CharField(required=True)
    created = serializers.DateTimeField(read_only=True)
    updated = serializers.DateTimeField(read_only=True)

    def create(self, validated_data):
        return Article.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        instance.body = validated_data.get('body', instance.title)
        instance.save()
        return instance

由于TextFieldDjango定义的针对大文本内容的扩展字段,所以在rest_framework中还是只能用CharField来序列化。覆写createupdate方法来定义调用serializer.save()时的行为。参数required=True表示必填,read_only=True表示只读。

shell

Django为我们提供了一个交互式的调试环境,输入命令python manage.py shell命令,进入交互环境。

先来看看序列化一个Article实例:

>>> from article.models import Article
>>> from article.serializers import ArticleSerializer
>>> from rest_framework.renderers import JSONRenderer
>>> from rest_framework.parsers import JSONParser
>>> article = Article(title="React", body="React is good")
>>> article.save()
>>> serializer = ArticleSerializer(article)
>>> serializer.data
{'id': 2, 'title': 'React', 'body': 'React is good', 'created': '2020-03-21T21:19:31.732703', 'updated': '2020-03-21T21:19:31.732728'}

之前通过序列化器将实例序列化为Python内置的字典类型,现在看看将其转为JSON

>>> content = JSONRenderer().render(serializer.data)
>>> content
b'{"id":2,"title":"React","body":"React is good","created":"2020-03-21T21:19:31.732703","updated":"2020-03-21T21:19:31.732728"}'

反序列化与上面类似,但步骤相反:

>>> import io
>>> stream = io.BytesIO(content)
>>> data = JSONParser().parse(stream)
>>> serializer = ArticleSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.validated_data
OrderedDict([('title', 'React'), ('body', 'React is good')])
>>> serializer.save()
<Article: Article object (3)> # 这里为3是因为我最初存了一个数据

ModelSerializer

REST framework为我们提供了一个更为简洁的编写序列化器的方式:

# 修改原本的ArticleSerializer类
class ArticleSerializer(serializers.ModelSerializer):

    class Meta:
        model = Article
        fields = ['id', 'title', 'body', 'created', 'updated']

可以在交互模式下看看:

>>> from article.serializers import ArticleSerializer
>>> serializer = ArticleSerializer()
>>> print(repr(serializer))
ArticleSerializer():
    id = IntegerField(label='ID', read_only=True)
    title = CharField(max_length=50)
    body = CharField(style={'base_template': 'textarea.html'})
    created = DateTimeField(read_only=True)
    updated = DateTimeField(read_only=True)
>>> 

ModelSerializer帮我们自动生成了所需的字段,并且拥有createupdate方法的默认实现。这是官方为我们提供的实现一个序列化器的快捷方式。注意到这里还对模型中的TextField类型的body做了特殊处理,定义了其渲染成HTML时的格式。

如果你对原生Django的表单熟悉,你会发现这个Serializer与原生的Form非常相似。

总结

现在我们熟悉了序列化反序列化,在下一篇文章中,我们将为我们的API编写一个新的视图(View)