14.3.序列化

介绍

本教程将介绍如何创建一个简单的高亮显示Web API的pastebin代码。在此过程中,它将介绍组成REST框架的各种组件,并让您全面了解所有组件如何组合在一起。

本教程相当深入,因此在开始之前,请准备好瓜子饮料。如果您只想快速浏览一下,请前往 quickstart 文档。

注意:本教程的代码已托管到在GitHub的 encode/rest-framework-tutorial中。网上的实现是用于测试的沙盒版本,可在此处获得。

设置新环境

在执行其他任何操作之前,我们将使用 venv创建一个新的虚拟环境。这将确保我们的程序包配置与我们正在处理的其他项目保持良好的隔离。

python3 -m venv env
source env/bin/activate

现在我们处于虚拟环境中,我们可以安装我们需要的软件包。

pip install django
pip install djangorestframework
pip install pygments  # 我们将用它来实现代码高亮

注意:若要退出虚拟环境,只需键入 deactivate。有关更多信息,请参阅venv文档.。

入门

好的,我们已经准备好了环境。现在,让我们开始创建一个新项目。

cd ~
django-admin startproject tutorial
cd tutorial

完成后,我们可以创建一个app,用它来创建一个简单的Web API。

python manage.py startapp snippets

我们需要将新创建的snippets app和rest_framework app添加到INSTALLED_APPS。让我们编辑tutorial/settings.py文件:

INSTALLED_APPS = [
    ...
    'rest_framework',
    'snippets.apps.SnippetsConfig',
]

好的,我们准备开始了。

创建要使用的模型

在本教程中,我们将从创建一个简单的Snippet model开始,该model用于存储代码片段。继续编辑 snippets/models.py 文件。

from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles

LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])


class Snippet(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
    style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)

    class Meta:
        ordering = ['created']

我们还需要为 snippet model创建初始的migration,并同步数据库。

python manage.py makemigrations snippets
python manage.py migrate

创建一个Serializer类

开始使用Web API的第一件事是提供一种将snippet实例序列化/反序列化为json等格式的方法。我们可以通过声明与Django的forms非常相似的serializers 来实现此目的。

snippets目录中创建一个名为serializers.py的文件,并添加以下内容。

from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES


class SnippetSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=False, allow_blank=True, max_length=100)
    code = serializers.CharField(style={'base_template': 'textarea.html'})
    linenos = serializers.BooleanField(required=False)
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

    def create(self, validated_data):
        """
        Create and return a new `Snippet` instance, given the validated data.
        """
        return Snippet.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        Update and return an existing `Snippet` instance, given the validated data.
        """
        instance.title = validated_data.get('title', instance.title)
        instance.code = validated_data.get('code', instance.code)
        instance.linenos = validated_data.get('linenos', instance.linenos)
        instance.language = validated_data.get('language', instance.language)
        instance.style = validated_data.get('style', instance.style)
        instance.save()
        return instance

serializer 类的第一部分定义了要进行序列化/反序列化的字段。create()update()方法定义了在调用serializer.save()时实例如何被创建和修改。

serializer 类与Django Form类非常相似,在各个字段上也包括相似的验证标志,例如requiredmax_lengthdefault

字段标志还可以控制在某些情况下(例如,呈现为HTML时)serializer 如何显示。上面的{'base_template': 'textarea.html'}标志等效于在Django Form类上使用widget=widgets.Textarea。这对于控制browsable API 如何显示尤其有用,我们将在本教程的后面部分看到。

实际上,通过使用 ModelSerializer 类,我们还可以节省一些时间,稍后我们会看到,而现在我们将保持serializer 定义的明确性。

使用Serializers

在继续之前,我们先熟悉一下新的Serializer类如何使用。让我们进入Django shell。

python manage.py shell

好的,一旦我们完成了一些导入操作后,就可以我们创建几个snippets 来使用。

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser

snippet = Snippet(code='foo = "bar"\n')
snippet.save()

snippet = Snippet(code='print("hello, world")\n')
snippet.save()

现在,我们得到一些snippets 实例。让我们序列化这些实例之一。

serializer = SnippetSerializer(snippet)
serializer.data
# {'id': 2, 'title': '', 'code': 'print("hello, world")\n', 'linenos': False, 'language': 'python', 'style': 'friendly'}

至此,我们已经将model实例转化为Python的原生数据类型,为了完成序列化过程,我们将数据渲染到json中。

content = JSONRenderer().render(serializer.data)
content
# b'{"id": 2, "title": "", "code": "print(\\"hello, world\\")\\n", "linenos": false, "language": "python", "style": "friendly"}'

反序列化是相似的。 首先,我们将流解析为Python的原生数据类型。

import io

stream = io.BytesIO(content)
data = JSONParser().parse(stream)

然后,我们将这些Python的原生数据类型还原到对象实例中。

serializer = SnippetSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# OrderedDict([('title', ''), ('code', 'print("hello, world")\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
serializer.save()
# <Snippet: Snippet object>

请注意,Serializers与django的Forms很相似。当我们开始使用serializer编写serializer时,相似性将变得更加明显。

我们还可以序列化querysets。为此,我们只需在serializer 参数中添加 many=True 标志。

serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [OrderedDict([('id', 1), ('title', ''), ('code', 'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', ''), ('code', 'print("hello, world")\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', ''), ('code', 'print("hello, world")'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]

Last updated

Was this helpful?