在咱们作任何事情以前,咱们将使用virtualenv建立一个新的虚拟环境。这将确保咱们的包配置与咱们正在开展的任何其余项目保持良好的隔离。html
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文档。python
好的,咱们准备好得到编码。要开始,咱们来建立一个新的项目来处理git
cd ~ django-admin.py startproject tutorial cd tutorial
一旦完成,咱们能够建立一个咱们将用来建立一个简单的Web API的应用程序。
python manage.py startapp snippets
咱们须要添加咱们的新snippets
应用和rest_framework
应用INSTALLED_APPS
。咱们来编辑tutorial/settings.py
文件:
snippetsrest_frameworkINSTALLED_APPStutorial/settings.py
INSTALLED_APPS = ( ... 'rest_framework', 'snippets.apps.SnippetsConfig', )
请注意,若是你使用的Django <1.9,则须要更换snippets.apps.SnippetsConfig
有snippets
。github
好的,咱们准备好了。web
为了本教程的目的,咱们将首先建立一个Snippet
用于存储代码片断的简单模型。继续编辑snippets/models.py
文件。注意:良好的编程实践包括评论。虽然您将在本教程代码的存储库版本中找到它们,但咱们在此忽略了它们,专一于代码自己。正则表达式
#coding=utf-8
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())
'''在models里面,用的models. '''
class Snippet(models.Model):
create = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100,blank=True,default='')
code = models.TextField() #文本
lineons = 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',) #关键字的高亮显示,排序方式是created 注意这里是一个元祖
咱们还须要为咱们的代码段模型建立初始迁移,并首次同步数据库。
python manage.py makemigrations snippets python manage.py migrate
咱们须要开始使用Web API的第一件事是提供一种将代码片断实例序列化和反序列化为表示形式的方法json
。咱们能够经过声明与Django表单很是类似的序列化器来作到这一点。在snippets
命名的目录中建立一个文件,serializers.py
并添加如下内容。shell
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES #从以前的models里面导入进来
'''views里面的全部字段,必需要与前面的models一致,尽量的原则是只能少,不能多'''
'''在serializer里面是 serializers. '''
class SnippetSerializer(serializers.Serializer): #Serializer是不可变的 Snippet是可变的,可是必定要和前面的models里面的要一致
id = serializers.IntegerField(read_only=True) #id是可读的,不能修改
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,validate_data):
return Snippet.objects.create(**validate_data)
#用于更新的函数
def update(self, instance, validated_data): #最后面instance.title 这是默认值
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
。django
字段标志还能够控制在某些状况下,如渲染到HTML时如何显示串行器。{'base_template': 'textarea.html'}
上面的标志至关于widget=widgets.Textarea
在Django Form
类上使用。这对于控制如何显示可浏览的API特别有用,咱们将在本教程的后面看到。
咱们实际上也能够经过使用ModelSerializer
课程来节省本身的时间,咱们稍后会看到,可是如今咱们将保持咱们的序列化器定义。
在咱们进一步了解以前,咱们将熟悉使用咱们新的Serializer类。咱们进入Django shell。
python manage.py shell
好的,一旦咱们有几个导入,咱们来建立一些代码片断来处理。
from snippets.models import Snippet from snippets.serializers import SnippetSerializer from rest_framework.renderers import JSONRenderer #输出格式为json格式 from rest_framework.parsers import JSONParser #输入格式为json格式 snippet = Snippet(code='foo = "bar"\n') #实例化类 snippet.save() snippet = Snippet(code='print "hello, world"\n') snippet.save()
咱们如今有几个片断实例能够玩。咱们来看看序列化这些实例之一。
此时,咱们将模型实例转换为Python本机数据类型。为了完成序列化过程,咱们将数据转换成。
serializer = SnippetSerializer(snippet) serializer.data #获取数据 python数据类型 # {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}json
content = JSONRenderer().render(serializer.data) #将python对象转化为json格式,由于前端传来的数据只支持json格式 content # b'{"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() # <Snippet: Snippet object>
请注意API与表单的使用状况。当咱们开始编写使用咱们的串行器的视图时,类似性将变得更加明显。
咱们也能够序列化查询集而不是模型实例。为此,咱们只many=True
须要为serializer参数添加一个标志。
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
类重构咱们的serializer 。snippets/serializers.py
再次打开该文件,并用SnippetSerializer
如下替换该类。
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ('id','title','code','linenos','language','style')
序列化器具备的一个不错的属性是能够经过打印其表示来检查序列化器实例中的全部字段。打开Django shell ,而后尝试如下操做:
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()
方法。咱们来看看咱们如何使用咱们的新的Serializer类编写一些API视图。目前咱们不会使用任何REST框架的其余功能,咱们只需将视图编写为常规的Django视图。
编辑snippets/views.py
文件,并添加如下内容。
from django.http import HttpResponse,JsonResponse #HTTP响应和json相应
from django.views.decorators.csrf import csrf_exempt #b不用跨域请求了
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from snippets.models import Snippet #从模型中引入
from snippets.serializers import SnippetSerializer #引入serializers
咱们的API的根本将是一个视图,支持列出全部现有的片断,或建立一个新的片断。
@csrf_exempt
def snippet_list(request): #生成列表,多条信息
#列出所有代码片断,或则建立新代码片断
if request.method == 'GET':
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets,many=True) #转成json格式
return JsonResponse(serializer.data,safe=False) #以json格式响应出去
elif request.method == 'POST':
data = JSONParser().parse(request) #解析发来的数据,用parse方法
serializer = SnippetSerializer(data=data)
if serializer.is_valid(): #验证数据是否合法
serializer.save()
return JsonResponse(serializer.data,status=201) #返回操做成功
return JsonResponse(serializer.errors,status=400) #返回操做错误
咱们的API的根本将是一个视图,支持列出全部现有的片断,或建立一个新的片断。
请注意,由于咱们但愿可以从不具备CSRF令牌的客户端对此视图进行POST,所以咱们须要将视图标记为csrf_exempt
。这不是你一般想要作的事情,REST框架视图实际上比这更有明确的行为,但它如今将用于咱们的目的。
咱们还须要一个与单个代码段对应的视图,并可用于检索,更新或删除代码段。
#设置容许能够跨域请求
@csrf_exempt
def snippet_detail(request, pk):
"""
提取 更新 删除代码片断
"""
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 == 'PATCH':#更新或者修改数据
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), #用户用正则表达式出入PK,传入到views里面 修改,更新接口 ]
咱们还须要在tutorial/urls.py
文件中链接根urlconf ,以包含咱们的片断应用程序的URL。
from django.conf.urls import url, include urlpatterns = [ url(r'^', include('snippets.urls')),
url(r'^admin/', admin.site.urls),
]
值得注意的是,咱们目前尚未正确处理的几个边缘案例。若是咱们发送格式错误json
,或者若是请求是使用视图不处理的方法,那么咱们最终会出现500个“服务器错误”响应。不过,如今这样作。
如今咱们能够启动一个服务咱们的代码片断的示例服务器。
退出外壳...
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
最后,咱们能够获得全部片断的列表:
或者咱们能够经过引用其id来获取特定的代码段:
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" } ]
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" }
一样,您能够经过在Web浏览器中访问这些URL来显示相同的json。
咱们到目前为止,咱们作得还不错,咱们有一个序列化API,与Django的Forms API和一些常规的Django视图很是类似。
咱们的API视图目前没有特别的特别之处,除了提供json
响应外,还有一些错误处理咱们仍然想要清理的边缘状况,但它是一个运行良好的Web API。