以下内容来源:Django-REST-Framework-Tutorial_zh-CN
Tutorial 1: 序列化 Serialization
1. 设置一个新的环境
在我们开始之前, 我们首先使用virtualenv要创建一个新的虚拟环境,以使我们的配置和我们的其他项目配置彻底分开。
$mkdir ~/env
$virtualenv ~/env/tutorial
$source ~/env/tutorial/bin/avtivate
现在我们处在一个虚拟的环境中,开始安装我们的依赖包
$pip install django
$pip install djangorestframework
$pip install pygments 使用这个包,做代码高亮显示
需要退出虚拟环境时,运行deactivate
。更多信息,virtualenv document
2. 开始
环境准备好只好,我们开始创建我们的项目
$ cd ~
$ django-admin.py startproject tutorial
$ cd tutorial
项目创建好后,我们再创建一个简单的app
$python manage.py startapp snippets
我们使用sqlite3
来运行我们的项目tutorial,编辑tutorial/settings.py
, 将数据库的默认引擎engine
改为sqlite3
, 数据库的名字NAME
改为tmp.db
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'tmp.db',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
同时更改settings.py
文件中的INSTALLD_APPS
,添加我们的APP snippets
和rest_framework
INSTALLED_APPS = (
...
'rest_framework',
'snippets',
)
在tutorial/urls.py
中,将snippets app的url包含进来
urlpatterns = patterns('',
url(r'^', include('snippets.urls')),
)
3. 创建Model
这里我们创建一个简单的snippets
model,目的是用来存储代码片段。
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, 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',)
完成model时,记得sync下数据库
python manage.py syncdb
4. 创建序列化类
我们要使用我们的web api,要做的第一件事就是序列化和反序列化, 以便snippets实例能转换为可表述的内容,例如json
. 我们声明一个可有效工作的串行器serializer。在snippets
目录下面,该串行器与django 的表单形式很类似。创建一个serializers.py
,并将下面内容拷贝到文件中。
from django.forms import widgets
from rest_framework import serializers
from snippets.models import Snippet
class SnippetSerializer(serializers.Serializer):
pk = serializers.Field() # Note: `Field` is an untyped read-only field.
title = serializers.CharField(required=False,
max_length=100)
code = serializers.CharField(widget=widgets.Textarea,
max_length=100000)
linenos = serializers.BooleanField(required=False)
language = serializers.ChoiceField(choices=models.LANGUAGE_CHOICES,
default='python')
style = serializers.ChoiceField(choices=models.STYLE_CHOICES,
default='friendly')
def restore_object(self, attrs, instance=None):
"""
Create or update a new snippet instance.
"""
if instance:
# Update existing instance
instance.title = attrs['title']
instance.code = attrs['code']
instance.linenos = attrs['linenos']
instance.language = attrs['language']
instance.style = attrs['style']
return instance
# Create new instance
return Snippet(**attrs)
该序列化类的前面部分,定义了要序列化和反序列化的类型,restore_object
方法定义了如何通过反序列化数据,生成正确的对象实例。
Notice that we can also use various attributes that would typically be used on form fields, such as widget=widgets.Textarea
. These can be used to control how the serializer should render when displayed as an HTML form. This is particularly useful for controlling how the browsable API should be displayed, as we’ll see later in the tutorial.
我们也可以使用ModelSerializer
来快速生成,后面我们将节省如何使用它。
5. 使用 Serializers
在我们使用我们定义的SnippetsSerializers之前,我们先熟悉下Snippets.
$python manage.py shell
进入shell终端后,输入以下代码:
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='print "hello, world"\n')
snippet.save()
我们现在获得了一个Snippets的实例,现在我们对他进行以下序列化
serializer = SnippetSerializer(snippet)
serializer.data
# {'pk': 1, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}
这时,我们将该实例转成了python原生的数据类型。下面我们将该数据转换成json
格式,以完成序列化:
content = JSONRenderer().render(serializer.data)
content
# '{"pk": 1, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'
反序列化也很简单,首先我们要将一个输入流(content),转换成python的原生数据类型
import StringIO
stream = StringIO.StringIO(content)
data = JSONParser().parse(stream)
然后我们将该原生数据类型,转换成对象实例
serializer = SnippetSerializer(data=data)
serializer.is_valid()
# True
serializer.object
# <Snippet: Snippet object>
注意这些API和django表单的相似处。这些相似点, 在我们讲述在view中使用serializers时将更加明显。
We can also serialize querysets instead of model instances. To do so we simply add a many=True
flag to the serializer arguments.
serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [{'pk': 1, 'title': u'', 'code': u'foo = "bar"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}, {'pk': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}]
6. 使用 ModelSerializers
SnippetSerializer
使用了许多和Snippet
中相同的代码。如果我们能把这部分代码去掉,看上去将更佳简洁。
类似与django提供Form
类和ModelForm
类,Rest Framework也包含了Serializer
类和 ModelSerializer
类。
打开snippets/serializers.py
,修改SnippetSerializer
类:
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
7. 通过Serializer编写Django View
让我们来看一下,如何通过我们创建的serializer类编写django view。这里我们不使用rest framework的其他特性,仅编写正常的django view。
我们创建一个HttpResponse 子类,这样我们可以将我们返回的任何数据转换成json
。
在snippet/views.py
中添加以下内容:
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
class JSONResponse(HttpResponse):
"""
An HttpResponse that renders it's content into JSON.
"""
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
我们API的目的是,可以通过view来列举全部的Snippet的内容,或者创建一个新的snippet
@csrf_exempt
def snippet_list(request):
"""
List all code snippets,