Django-Rest-Framework 教程: 1. 序列化 (Serialization)

在本篇中, 我们将通过建立一个代码黏贴板(pastebin), 来熟悉组成REST framework的各组成部分, 并了解这些部件是如何相互协调工作的.

1. 环境设置

首先我们使用virtualenvwrapper创建新的virtualenv, 并安装需要的代码库:

    mkvirtualenv env
    pip install django
    pip install djangorestframework
    pip install pygments # 用于代码高亮

2. Django项目设置

我们建立Django项目tutorial, 和app snippets

    django-admin.py startproject tutorial
    cd tutorial
    python manage.py startapp snippets

设置settings.py:

    # tutorial/settings.py
    DATABASES = {
        ‘default‘: {
            ‘ENGINE‘: ‘django.db.backends.postgresql_psycopg2‘,
            ‘NAME‘: ‘database_name‘,
            ‘USER‘: ‘database_user‘,
            ‘PASSWORD‘: ‘database_password‘,
            ‘HOST‘: ‘‘,
            ‘PORT‘: ‘‘
        }
    }

    INSTALLED_APPS = (
    ...
    ‘rest_framework‘,
    ‘snippets‘,
    )

设置urls.py, 将新建的snippet app中的urls.py加入到其中:

    # tutorial/urls.py
    urlpatterns = patterns(‘‘,
        url(r‘^‘, include(‘snippets.urls‘)),
    )

3. 创建Model

我们建立Snippet Model用于储存代码:

    # snippet/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‘,)

启动django服务器:

    python manage.py syncdb

4. 创建Serializer

第一步我们需要为我们的API提供序列化和反序列化的方法, 将snippet实例转为json等方式呈现数据. 我们可以使用Serializer达到这一目的, Serializer和django forms十分相似. 我们建立snippet/serializers.py文件:

    # snippets/serializers.py
    from django.forms import widgets
    from rest_framework import serializers
    from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES

    class SnippetSerializer(serializers.Serializer):
        pk = serializers.Field()  # `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=LANGUAGE_CHOICES,
                                           default=‘python‘)
        style = serializers.ChoiceField(choices=STYLE_CHOICES,
                                        default=‘friendly‘)

        def restore_object(self, attrs, instance=None):
            """
            创建或更新一个snippet实例, 返回该snippet实例

            如果不定义该function, 则反序列化时将返回一个包括所有field的dict
            """
            if instance:
                # 更新已存在的snippet实例
                instance.title = attrs.get(‘title‘, instance.title)
                instance.code = attrs.get(‘code‘, instance.code)
                instance.linenos = attrs.get(‘linenos‘, instance.linenos)
                instance.language = attrs.get(‘language‘, instance.language)
                instance.style = attrs.get(‘style‘, instance.style)
                return instance

            # Create new instance
            return Snippet(**attrs)

以上代码第一部分定义了序列化和反序列化的项, 第二部分restore_object function则定义了符合要求的已序列化snippet实例如何反序列化.

注意, 我们也可以使用在django form中使用的参数, 比如widget=widgets.Textarea. 这些参数可以控制serializer如何显示为HTML form, 尤其是在构建可浏览的API时, 十分有用, 我们也会在今后的博文中详细介绍.

如果想快速的构建serializer, 我们也可以使用ModelSerializer, 我们会在稍后介绍:

5. 使用serializer

在继续完成该项目前, 我们先熟悉一下serializer, 是有manage.py shell启动django shell:

    python manage.py shell

import必要的代码库并创建2个snippet实例:

    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()

序列化其中一个实例:

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

以上代码已将snippet实例转化为Python基本数据类型, 接下来我们完成序列化:

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

反序列化也是类似的, 首先将stream转为python基本类型:

    # 根据我们使用的是 python 2 或是 python 3
    # 这一import会自动引入 `StringIO.StringIO` 或 `io.BytesIO`
    from rest_framework.compat import BytesIO

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

然后我们将它转化为snippet实例:

    serializer = SnippetSerializer(data=data)
    serializer.is_valid()
    # True
    serializer.object
    # <Snippet: Snippet object>

可见, serializer和django form 有多么相似, 当我们写view时, 这一相似性会更加明显.

当我们输入参数many=True时, serializer还能序列化queryset:

    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中, 包含了许多与model重复的field, 那么是否能将这些代码变得更紧凑呢? 当然可以!

就像Django提供ModelForm一样, django_rest_framework提供了ModelSerializer.

我们修改之前的SnippetSerializer:

    #snippets/serializers.py
    class SnippetSerializer(serializers.ModelSerializer):
        class Meta:
            model = Snippet
            fields = (‘id‘, ‘title‘, ‘code‘, ‘linenos‘, ‘language‘, ‘style‘)

7. 在Views中使用Serializer

以下代码中, 为了更好的理解Serializer, 我们只使用django_rest_framework的Serializer部件和Django最基本的function_base_view.

首先创建能返回json数据的HttpResponse:

    # snippets/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):
        """
        将内容转为JSON格式的HttpResponse
        """
        def __init__(self, data, **kwargs):
            content = JSONRenderer().render(data)
            kwargs[‘content_type‘] = ‘application/json‘
            super(JSONResponse, self).__init__(content, **kwargs)

我们API的根目录是一个list view, 用于展示所有存在的snippet, 或建立新的snippet:

    # snippets/views.py
    @csrf_exempt
    def snippet_list(request):
        """
        展示所有存在的snippet, 或建立新的snippet
        """
        if request.method == ‘GET‘:
            snippets = Snippet.objects.all()
            serializer = SnippetSerializer(snippets, many=True)
            return JSONResponse(serializer.data)

        elif request.method == ‘POST‘:
            data = JSONParser().parse(request)
            serializer = SnippetSerializer(data=data)
            if serializer.is_valid():
                serializer.save()
                return JSONResponse(serializer.data, status=201)
            return JSONResponse(serializer.errors, status=400)

注意, 为了简便, 我们希望在POST时不使用csrf, 因此使用了csrf_exempt. 这不是通常应该做的, 而且django_rest_framework默认使用了更为安全的方式.

用于展示, 更新或删除的view:

    # snippets/views.py
    @csrf_exempt
    def snippet_detail(request, pk):
        """
        展示, 更新或删除一个snippet
        """
        try:
            snippet = Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            return HttpResponse(status=404)

        if request.method == ‘GET‘:
            serializer = SnippetSerializer(snippet)
            return JSONResponse(serializer.data)

        elif request.method == ‘PUT‘:
            data = JSONParser().parse(request)
            serializer = SnippetSerializer(snippet, data=data)
            if serializer.is_valid():
                serializer.save()
                return JSONResponse(serializer.data)
            return JSONResponse(serializer.errors, status=400)

        elif request.method == ‘DELETE‘:
            snippet.delete()
            return HttpResponse(status=204)

最后修改urls.py, 使这些view通电

    # snippets/urls.py
    from django.conf.urls import patterns, url

    urlpatterns = patterns(‘snippets.views‘,
        url(r‘^snippets/$‘, ‘snippet_list‘),
        url(r‘^snippets/(?P<pk>[0-9]+)/$‘, ‘snippet_detail‘),
    )

需要注意的是, 我们还有许多错误处理没有涉及, 例如提交错误的json, 使用view不支持的http method等. 同样处于更好的理解serializer的目的, 这些错误都会返回500错误页.

8. 测试

首先我们推出shell:

    quit()

启动django server:

    python manage.py runserver

在另外的终端中:

curl http://127.0.0.1:8000/snippets/

[{"id": 1, "title": "", "code": "foo = \"bar\"\n", "linenos": false, "language": "python", "style":
    "friendly"}, {"id": 2, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language":
    "python", "style": "friendly"}]

或者我们使用id获取一个snippet:

    curl http://127.0.0.1:8000/snippets/2/

    {"id": 2, "title": "", "code": "print \"hello, world\"\n", "linenos": false,
    "language": "python", "style": "friendly"}

同样, 我们也可以使用浏览器测试这些API.

原文链接: http://www.weiguda.com/blog/19/

时间: 2024-10-14 16:55:12

Django-Rest-Framework 教程: 1. 序列化 (Serialization)的相关文章

Django REST framework 中的序列化器

在此之前定义一个序列化工具: views中的的代码 from rest_framework.viewsets import ModelViewSet from .models import BookInfo from .serializers import BookInfoSerializers class BookInfoViewSet(ModelViewSet): queryset = BookInfo.objects.all() # 取序列化模型 serializer_class = Bo

Django Rest Framework --- 序列化组件

一.序列化组件的作用 在前后端分离开发时,前端与后端用来交互的数据的格式是一致的(数据格式为字符串的json数据),于是后端程序员在传递数据时,便要将数据封装成符合格式的数据,如果不借助方法,手动进行数据封装,会非常的浪费时间,在Django rest framework中的序列化组件帮我们解决了这个问题. 二.Django自带的序列化组件 from django.core import serializers def test(request): book_list = Book.object

DRF (Django REST framework) 框架介绍

Web应用模式 在开发Web应用中,有两种应用模式: 前后端不分离 前后端分离 1 前后端不分离 在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与后端的耦合度很高. 这种应用模式比较适合纯网页应用,但是当后端对接App时,App可能并不需要后端返回一个HTML网页,而仅仅是数据本身,所以后端原本返回网页的接口不再适用于前端App应用,为了对接App后端还需再开发一套接口. 2 前后端分离 在前后端分离的应用模式中,后端仅返

Django REST framework视图

Django REST framework视图 学习序列化的时候发现有大量的冗余代码,所以我们要使用Django REST framework里的视图减少我们的代码 DRF中的request 在Django REST Framework中内置的Request类扩展了Django中的Request类,实现了很多方便的功能--如请求数据解析和认证等. 比如,区别于Django中的request从request.GET中获取URL参数,从request.POST中取某些情况下的POST数据. 在API

Django REST framework框架详解

Django REST framework 简介 在序列化与反序列化时,虽然操作的数据不尽相同,但是执行的过程却是相似的,也就是说这部分代码是可以复用简化编写的. 在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增.删.改.查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的: 增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回 删:判断要删除的数据是否存在 -> 执行数据库删除 改:判断要修改的数据是否存在 -&g

【Django】Django REST Framework简单教程

Django REST Framework使用案例和教程 什么是Django REST Framework?简单说就是一款快速构建REST风格API的框架.能够以很少的代码和很简单的方式在Django项目中构建符合REST风格的API.十分适合Django框架的后端的编写 本文参考 https://blog.csdn.net/weixin_40193776/article/details/81210215,教程原文非常详细,还带图片.本文做了顺序上的修改以符合从无到有建立REST Framewo

Django Rest framework序列化流程

目录 一 什么是序列化 二 Django REST framework配置流程之Serializer 三 Django REST framework配置流程之ModelSerializer 一 什么是序列化 序列化模型与序列化关系模型 序列化模型,顾名思义,即对 models 里的数据模型作序列化. 而序列化关系模型则是对 models 里数据模型中带有关系的如 ForeignKey, ManyToManyField 和 OneToOneField 字段作序列化. Django Rest Fra

Django Rest Framework(2)-----序列化详解(serializers)

REST framework中的序列化类与Django的Form和ModelForm类非常相似.我们提供了一个Serializer类,它提供了一种强大的通用方法来控制响应的输出,以及一个ModelSerializer类,它为创建处理模型实例和查询集的序列化提供了有效的快捷方式. Serializers 序列化器允许把像查询集和模型实例这样的复杂数据转换为可以轻松渲染成JSON,XML或其他内容类型的原生Python类型.序列化器还提供反序列化,在验证传入的数据之后允许解析数据转换回复杂类型.不仅

Django REST framework序列化

Django REST framework序列化 开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式 models部分 from django.db import models class Book(models.Model): title = models.CharField(max_length=32) price = models.IntegerField() pub_date = models.DateFie