Django REST FrameWork中文教程1:序列化
介绍 本教程将介绍创建一个突出显示Web API的简单PasteBinder代码。 一路上,它将介绍构成REST框架的各种组件,并让您全面了解如何将所有内容组合在一起。 该教程是相当深入的,所以你应该得到一个饼干和一杯你最喜欢的brew,然后开始。 如果您只想快速浏览一下,则应该转到快速入门文档。 注意:本教程的代码可以在GitHub的tomchristie / rest-framework-tutorial存储库中找到。 完成的实现也在线作为沙箱版本进行测试,可以在这里找到。 建立环境 在我们做任何事情之前,我们将使用virtualenv创建一个新的虚拟环境。 这将确保我们的软件包配置与我们正在进行的其他任何项目保持良好的隔离。 virtualenv envsource?env/bin/activate 现在我们进入了virtualenv环境,我们可以安装我们的软件包需求。 pip?install?django pip?install?djangorestframework pip?install?pygments??#?我们将使用这个让代码突出显示 注意:要随时退出virtualenv环境,只需键入 准备开始 好的,我们准备好了编码。 首先,让我们创建一个新的项目来处理。
cd?~ django-admin.py?startproject?tutorial cd?tutorial 一旦完成,我们可以创建一个应用程序,我们将用它来创建一个简单的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.apps.SnippetsConfig有snippets。 好的,我们准备好了。 创建一个可以使用的模型 为了本教程的目的,我们首先创建一个Snippet 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',) 执行makemigrations和migrate命令,进行数据库迁移 python?manage.py?makemigrations?snippets python?manage.py?migrate 创建一个Serializer类 我们需要开始使用Web API的第一件事是提供一种将代码片段实例序列化和反序列化为表示形式(如json)的方法。 我们可以通过声明与Django的表单非常相似的序列化器来实现这一点。 在名为serializers.py的snippets目录中创建一个文件并添加以下内容。 from?rest_framework?import?serializers from?snippets.models?import?Snippet,?LANGUAGE_CHOICES,?STYLE_CHOICES class?SnippetSerializer(serializers.Serializer): ????#?每一个表都可以建一个serializer,类似Django的Form??专门用于json ????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时。 上面的{'base_template':'textarea.html'}标志等同于在Django Form类上使用widget = widgets.Textarea。 这对于控制如何显示可浏览的API特别有用,正如我们将在本教程后面看到的。 我们实际上也可以通过使用ModelSerializer类来节省一些时间,稍后我们会看到,但现在我们将保持我们的序列化程序定义清晰。 使用Serializer 在我们进一步了解之前,我们将熟悉使用我们的新的Serializer类。让我们进入Django shell。 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='foo?=?"bar"n') snippet.save() snippet?=?Snippet(code='print?"hello,?world"n') snippet.save() 我们现在获得了一个Snippets的实例,现在我们对他进行以下序列化 ### ?该代码是把刚刚保存的数据snippet对象,经过序列化保存成一个字典 ?????snippet?=?Snippet(code='print?"hello,?world"n') ?????snippet.save() ????? ### 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。 #?将字典转换成json格式 content?=?JSONRenderer().render(serializer.data) content #?'{"id":?2,?"title":?"",?"code":?"print?"hello,?world"n",?"linenos":?false,?"language":?"python",?"style":?"friendly"}' 反序列化是相似的。 首先,我们将一个流解析为Python数据类型 #?将json转换成字典格式 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()????#?保存数据 #?<Snippet:?Snippet?object> 注意API与表单的使用情况。当我们开始编写使用我们的序列化器的视图时,相似性应该变得更加明显。 我们也可以序列化查询集而不是模型实例。为此,我们只 serializer?=?SnippetSerializer(Snippet.objects.all(),?many=True) serializer.data #?[OrderedDict([('id',?1),?('title',?u''),?u'foo?=?"bar"n'),?'friendly')]),?OrderedDict([('id',?2),?u'print?"hello,?3),?world"'),?'friendly')])] 使用ModelSerializers
与Django提供的 我们使用 class?SnippetSerializer(serializers.ModelSerializer): ????#?ModelSerializer和Django中ModelForm功能相似 ????#?Serializer和Django中Form功能相似 ????class?Meta: ????????model?=?Snippet ????????fields?=?('id',?'title',?'code',?'linenos',?'language',?'style') 序列化程序所具有的一个不错的属性是,您可以通过打印其表示来检查序列化程序实例中的所有字段。 from?snippets.serializers?import?SnippetSerializer serializer?=?SnippetSerializer() print(repr(serializer)) #?SnippetSerializer(): #????id?=?IntegerField(label='ID',?read_only=True) #????title?=?CharField(allow_blank=True,?max_length=100,?required=False) #????code?=?CharField(style={'base_template':?'textarea.html'}) #????linenos?=?BooleanField(required=False) #????language?=?ChoiceField(choices=[('Clipper',?'FoxPro'),?('Cucumber',?'Gherkin'),?('RobotFramework',?'RobotFramework'),?('abap',?'ABAP'),?('ada',?'Ada')... #????style?=?ChoiceField(choices=[('autumn',?'autumn'),?('borland',?'borland'),?('bw',?'bw'),?('colorful',?'colorful')... 重要的是要记住
使用我们的Serializer编写正常的Django视图 我们来看看我们如何使用新的Serializer类编写一些API视图。目前,我们不会使用任何REST框架的其他功能,我们只需将视图编写为常规的Django视图。 编辑 from?django.http?import?HttpResponse,?JsonResponse 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 我们API本来是一个视图函数,支持监听所有已有的代码或者新建的代码片段 @csrf_exempt def?snippet_list(request): ????""" ????List?all?code?snippets,?or?create?a?new?snippet. ????""" ????if?request.method?==?'GET': ????????snippets?=?Snippet.objects.all() ????????serializer?=?SnippetSerializer(snippets,?many=True) ????????return?JsonResponse(serializer.data,?safe=False) ????elif?request.method?==?'POST': ????????data?=?JSONParser().parse(request) ????????serializer?=?SnippetSerializer(data=data) ????????if?serializer.is_valid(): ????????????serializer.save() ????????????#?serializer.data?数据创建成功后所有数据 ????????????return?JsonResponse(serializer.data,?status=201) ????????#?serializer.errors?错误信息 ????????return?JsonResponse(serializer.errors,?status=400) 请注意,因为我们希望能够从不具有CSRF令牌的客户端POST到此视图,所以我们需要将该视图标记为csrf_exempt。 这不是你通常想要做的事情,而REST框架视图实际上使用比这更明智的行为,但它现在就可以用于我们的目的。 我们还需要一个与单个代码片段相对应的视图,可以用来检索,更新或删除代码片段。 @csrf_exempt def?snippet_detail(request,?pk): ????""" ????Retrieve,?update?or?delete?a?code?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) 最后我们需要把这些观点连接起来。创建 from?django.conf.urls?import?url from?snippets?import?views urlpatterns?=?[ ????url(r'^snippets/$',?views.snippet_list),????url(r'^snippets/(?P<pk>[0-9]+)/$',?views.snippet_detail),] 我们还需要在 from?django.conf.urls?import?url,?include urlpatterns?=?[ ????url(r'^',?include('snippets.urls')),] 值得注意的是,我们目前还没有处理好几个边缘案例。如果我们发送 测试我们在Web API上的第一次尝试 现在我们可以启动一个服务我们的代码片段的示例服务器。 退出shell... quit() 并启动Django的开发服务器。 python?manage.py?runserver Validating?models... 0?errors?found Django?version?1.11,?using?settings?'tutorial.settings' Development?server?is?running?at?http://127.0.0.1:8000/ Quit?the?server?with?CONTROL-C. 在另一个终端窗口中,我们可以测试服务器。 我们可以使用curl或httpie来测试我们的API?。Httpie是用Python编写的用户友好的http客户端。 您可以使用pip安装httpie: pip?install?httpie 最后,我们可以得到所有片段的列表: http?http://127.0.0.1:8000/snippets/HTTP/1.1?200?OK...[ ??{ ????"id":?1,????"title":?"",????"code":?"foo?=?"bar"n",????"linenos":?false,????"language":?"python",????"style":?"friendly" ??},??{ ????"id":?2,????"code":?"print?"hello,?world"n",????"style":?"friendly" ??}] 或者我们可以通过引用其id来获取特定的代码段: http?http://127.0.0.1:8000/snippets/2/ HTTP/1.1?200?OK ... { ??"id":?2,??"title":?"",??"code":?"print?"hello,??"linenos":?false,??"language":?"python",??"style":?"friendly" } 同样,您可以通过在Web浏览器中访问这些URL来显示相同的json。 我们现在在哪 目前为止,我们已经有了一个序列化API,它与Django的Forms API以及一些常规的Django视图非常相似。 除了服务json响应之外,我们的API视图目前没有做特别特别的事情,还有一些我们仍然希望清理的错误处理边缘案例,但这是一个正常运行的Web API。 我们将在本教程的第2部分中看到我们如何开始改进事情。 Django REST FrameWork中文文档目录: Django REST FrameWork 中文教程1:序列化 Django REST FrameWork 中文教程2:请求和响应 Django REST FrameWork 中文教程3:基于类的视图 Django REST FrameWork 中文教程4:验证和权限 Django REST FrameWork 中文教程5:关系和超链接API Django REST FrameWork 中文教程6: ViewSets&Routers Django REST FrameWork 中文教程7:模式和客户端库 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |