介绍
本教程将介绍如何创建一个简单的 pastebin 代码,突出显示Web API。 通过这个过程,将介绍构成REST框架的各种组件,并全面了解这一切是如何融合在一起的。
该教程是相当深入的,所以你应该在开始之前准备好曲奇饼干和一杯你最喜爱的佳酿。 如果您只需要快速概述,您应该转到快速入门文档。
注意:本教程的代码在GitHub的tomchristie / rest-framework-tutorial存储库中可用。 完成的实现也是在线作为沙盒版本进行测试,可在这里获得。
建立一个新的环境
在我们做任何事情之前,我们将使用virtualenv创建一个新的虚拟环境。 这将确保我们的包配置与我们正在开展的任何其他项目保持良好的隔离。
virtualenv env
source env/bin/activate
现在我们在一个virtualenv环境中,根据需求安装我们的包。
pip install django
pip install djangorestframework
pip install pygments # We'll be using this for the code highlighting
注意:随时想要退出virtualenv环境时,只需键入deactivate。 有关更多信息,请参阅virtualenv文档。
入门
好了,我们准备开始编码了。首先,我们先创建一个工作项目。
cd ~
django-admin.py startproject tutorial
cd tutorial
完成后,我们可以创建一个app以便来创建简单的WEB API。
python manage.py startapp snippets
我们需要将新的snippets应用程序和rest_framework应用程序添加到INSTALLED_APPS。 我们来编辑tutorial / settings.py文件:
INSTALLED_APPS = (
...
'rest_framework',
'snippets.apps.SnippetsConfig',
)
请注意,如果你使用Django <1.9,则需要使用snippets替换snippets.apps.SnippetsConfig。
现在我们准备好了。
创建一个可以使用的模型
本教程的目的是为了创建一个用于存储代码片段的简单的Snippet模型。 继续编辑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模型创建初始迁移,并首次同步数据库。
python manage.py makemigrations snippets
python manage.py migrate
创建一个序列化类
首先,我们需要开始Web API的第一件事是提供一种讲snippet实例序列化和反序列化为诸如json形式的方法。我们可以声明和Django表单非常相似的序列化器来实现。在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
序列化器类的第一部分定义了序列化/反序列化的字段。 create()和update()方法定义了在调用serializer.save()时如何创建或修改完整的实例。
序列化器类与Django Form类非常相似,并在各种字段中包含类似的验证标志,例如required,max_length和default。
在某些情况下,字段标志还可以控制序列化如何显示,例如渲染到HTML时。
字段标志还可以控制在某些情况下,如渲染到HTML时如何显示串行器。 上面的{'base_template':'textarea.html'}标志等同于在Django Form类上使用widget = widgets.Textarea。 这对于控制如何显示可浏览的API特别有用,我们将在本教程的后面看到。
使用序列化
在我们进一步了解之前,我们将熟悉使用我们的新的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()
我们现在有几个snippet 实例可以玩。 我们来看看序列化这些实例中的一个。
serializer = SnippetSerializer(snippet)
serializer.data
# {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}
此时,我们将模型实例转换为Python原生数据类型。 将数据传给json,完成序列化过程。
content = JSONRenderer().render(serializer.data)
content
# '{"id": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'
反序列化是类似的。 首先我们将一个流解析为Python原生数据类型...
from django.utils.six import BytesIO
stream = BytesIO(content)
data = JSONParser().parse(stream)
...然后我们将这些原生数据类型恢复到对象实例中。
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()
#
请注意API如何与表单一起使用。 当我们开始使用serializer编写views 时,相似性应该会变得更加明显。
我们也可以序列化querysets 而不是model 实例。 为了做到这一点,我们只需要为serializer参数添加一个many=True的标志。
serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', u''), ('code', u'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', u''), ('code', u'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]