安装咱们依赖的包
pip install pygments # 代码高亮插件
咱们就能够建立一个应用,咱们将会用他来建立简单的Web API。html
python manage.py startapp snippets
添加一个新的snippets
应用和rest_framework
应用到INSTALLED_APPS
。让咱们编辑tutorial/settings.py
文件:python
INSTALLED_APPS = ( ... 'rest_framework', 'snippets.apps.SnippetsConfig', )
.web
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模型建立一个初始迁移(initial migration),而后第一次同步数据库。shell
python manage.py makemigrations snippets
python manage.py migrate
着手咱们的Web API,首先要作的是,提供一种将咱们的snippet
实例序列化/反序列化成例如json
这样的表述形式。咱们能够经过声明序列来完成,这些序列与Django
的表单(forms)
工做类似。在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 class)的第一部分定义了一些须要被序列化/反序列化字段。create()
和update()
方法定义了在调用serializer.save()
时成熟的实例是如何被建立和修改的。 序列化类(serializer class)与Django的表单类(Form class)很是类似,包括对各类字段有类似的确认标志(flag),例如required
,max_length
和default
。 在某些状况下,这些字段标志也能控制序列应该怎么表现,例如在将序列渲染成HTML时。{'base_template': 'textarea.html}'
标志至关于对Django表单(Form)类使用widget=widgets.Textarea
。这对控制API的显示尤为有用,之后的教程将会看到。 事实上,之后咱们能够经过使用ModelSerializer
类来节约咱们的时间,可是如今为了让咱们序列化定义更清晰,咱们用Serializer类。django
在咱们深刻以前,咱们须要熟练使用新的序列化列(Serializer class)。然咱们开始使用Django命令行吧。json
python manage.py shell
如今咱们已经有了一些snippet实例。让咱们看看如何将其中一个实例序列化。api
serializer = SnippetSerializer(snippet) serializer.data # {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}
如今,咱们已经将模型实例(model instance)转化成Python原生数据类型。为了完成实例化过程,咱们要将数据渲染成json。浏览器
content = JSONRenderer().render(serializer.data) content # '{"id": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'
反序列化也同样。首先,咱们须要将流(stream)解析成Python原生数据类型...服务器
from django.utils.six import BytesIO stream = 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>
能够看到,API和表单(forms)是多么类似啊。当咱们用咱们的序列写视图的时候,类似性会至关明显。 除了将模型实例(model instance)
序列化外,咱们也能序列化查询集(querysets)
,只须要添加一个序列化参数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')])]
咱们的SnippetSerializer
类复制了包含Snippet
模型在内的不少信息。若是咱们能简化咱们的代码,那就更好了。 以Django
提供表单(Form)
类和模型表单(ModelForm)
类相同的方式,REST
框架包括了实例化(Serializer)
类和模型实例化(ModelSerializer)
类。 咱们来看看用ModelSerializer
类建立的序列。再次打开snippets/serializers.py
文件,用下面的代码重写SnippetSerializer
类。
class SnippetSerializer(serializers.ModelSerializer): class Meta: model = Snippet fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
序列一个很是棒的属性就是,你可以经过打印序列实例的结构(representation)
查看它的全部字段。输入python manage.py shell
打开命令行,而后尝试如下代码:
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')...
记住,ModelSerializer
类并无作什么有魔力的事情,它们仅仅是一个建立序列化类的快捷方式。
create()
和update()
方法的实现。让咱们看看,使用咱们新的序列化类,咱们怎么写一些API视图。此刻,咱们不会使用REST框架的其余特性,仅仅像写常规Django视图同样。 经过建立HttpResponse
的一个子类来开始,其中,咱们能够用这个子类来渲染任何咱们返回的json
数据。 编辑snippets/views.py
文件,添加如下代码。
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将是一个支持列出全部存在的snippets
的视图,或者建立一个新的snippet
对象。
@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() return JsonResponse(serializer.data, status=201) return JsonResponse(serializer.errors, status=400)
注意,由于咱们但愿能够从没有CSRF token
的客户端POST
数据到这个视图,咱们须要标记这个视图为csrf_exempt
。一般,你并不想这么作,而且事实上REST框架视图更实用的作法不是这样的,可是目前来讲,这足以到达咱们的目的。 咱们也须要一个与单个snippet
对象相应的视图,而且咱们使用这个视图来读取、更新或者删除这个snippet
对象。
@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)
最终,咱们须要用线将这些视图连起来。建立snippets/urls.py文件:
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), ]
咱们也须要在根url配置文件tutorial/urls.py中添加咱们的snippet应用URL。
from django.conf.urls import url, include urlpatterns = [ url(r'^', include('snippets.urls')), ]
有一些当时咱们没有正确处理的边缘事件是没有价值的。若是咱们发送不正确的json数据,或者若是咱们制造了一个视图没有写处理的方法(method),那么咱们会获得500“服务器错误”的响应。固然,如今也会出现这个问题。
如今咱们开始建立一个测试服务器来服务咱们的snippets应用。 退出命令行......
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是一个面向用户的很是友好的http客户端,它是用Python写的。让咱们来安装它。 你能够经过pip来安装httpie:
pip install httpie
最后,咱们来获取一个包含全部snippets的列表:
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, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly" } ]
或者咱们能够经过id来获取指定的snippet:
http http://127.0.0.1:8000/snippets/2/ HTTP/1.1 200 OK ... { "id": 2, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly" }
类似地,你能够经过在浏览器中访问这些连接来得到相同的json数据。
到目前为止,咱们作的都很好,咱们已经得到一个序列化API,这和Django的表单API很是类似,而且咱们写好了一些经常使用的Django视图。 如今,咱们的API视图除了服务于json外,不会作任何其余特别的东西,而且有一些错误咱们仍然须要清理,可是它是一个可用的Web API。
扫码关注微信公众号 “小樊Study”获取更多
直男们,扫我送女朋友哟!