官網地址html
本教程將會介紹建立一個簡單webAPI。在整個學習的過程當中,將會逐一介紹到REST framework的各類組件,讓你全面的瞭解全部東西是若是組合在一塊兒的。
這個教程將會至關的詳細,因此在開始以前,你應該去來點餅乾,再喝上一些你喜歡的飲料。若是你只是想快速概覽,你應該查看Quickstart.
注意:本教程的代碼能夠在GitHub的 tomchristie/rest-framework-tutorial中找到。測試,這是一個測試連接。python
使用 virtualenv
建立一個虛擬環境.git
virtualenv env source env/bin/activate
而後咱們在咱們建立的虛擬環境中安裝須要的包。github
pip install django pip install djangorestframework pip install pygments #使用它來代碼高亮
注意:使用 deactivate
來隨時退出虛擬環境。更多的信息請查看Virtualenv documentationweb
咱們這邊開始編寫代碼了。先來建立一個項目吧~shell
cd ~ django-admin.py startproject tutorial cd tutorial
接下來,咱們建立一個app。django
python manage.py startapp snippets
咱們須要添加 snippets
和 rest_framework
到 INSTALLED_APPS
,在 tutorial/settings.py
文件中:json
INSTALLED_APPS = { ... 'rest_framework', 'snippets.apps.SnippetsConfig', }
注意:若是你使用的django<1.9,你須要替換 snippets.apps.SnippetsConfig
爲snippets
。
咱們能夠繼續上路了。segmentfault
在本教程中,咱們將建立一個簡單的model,這個model將用於儲存代碼片斷。
編輯 snippets/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,defalut='') 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')
執行命令,建立數據表:
python manage.py makemigrations snippets python manage.py migrate
首先,咱們須要給咱們的web API 提供一種序列化和反序列化的呈現方式,如json
。
咱們能夠申明一個和django的forms差很少的serializers。建立一個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): return Snippet.objects.create(**validated_data) def update(self,instance,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的第一步是定義須要 序列化/反序列化 的字段。create()
和update()
方法定義當serializer.save()
時,若是建立和更新。
serializer類很是相似於Django的Form
類。包括各個字段的驗證標記,例如 required
,max_length
,default
。
字段標記也可以控制serializer在某些環境中如何顯示,例如呈現爲HTML.
以前的{'base_template': 'textarea.html'}標記至關於django
Form中的
widget=widgets.Textarea`。
其實咱們使用ModelSerializer
類更可以節省咱們的時間,但如今,咱們仍是顯示的定義咱們的字段。
在咱們更進一步學習以前,咱們將經過django shell
來熟悉serializer。
python manage.py shell
咱們須要導入咱們須要的東西,而後建立兩個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 # {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}
在這裏,咱們翻譯這個model實例爲python原生的數據類型,爲了完成序列化,咱們將數據呈現爲JSON。
content = JSONRenderer().render(serializer.data) content # '{"id": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'
反序列化相似。首先,咱們解析一個流爲Python原生數據類型。
from django.utils.six import BytesIO 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>
注意:這相似於forms.當咱們編寫views使用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 framework也包含Serializer
和ModelSerializer
兩個類。
讓咱們來使用ModelSerializer
來重構咱們的serializer類。打開snippets/serializers.py
,替換SinppetSerializer
類:
class SnippetSerializer(serializers.ModelSerizer): class Meta: model = Snippet fields = ('id','title','code','linenos','language','style')
serializer擁有一個很好的屬性,你可以經過打印查看一個serializer實例的全部字段。打開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
不會作任何如魔法般的事情,它只是更快捷的建立serializer
create()
和update()
方法讓咱們使用咱們新的serializer來寫一些API視圖吧。在這裏,咱們不會使用任何REST framework的其餘特性,咱們就寫一個常規的 django views。
來編寫 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將會支持查看全部數據和建立一個新的snippet
@csrf_exempt def snippet_list(request): """ 顯示全部的代碼片斷,或者建立一個新的片斷 """ 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)
注意:由於咱們但願post可以不經過CSRF token的驗證,因此咱們使用了 csrf_exempt
。事實上,這不會是你常常作的事情,而且REST framework views會更加明智的作這個事情。可是如今,他可使用。
咱們還須要這個視圖可以檢索,更新和刪除。
@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)
最後,咱們須要建立url,在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), ]
咱們還須要在跟urls.py(tutorial/urls.py
)上引入咱們的urls.py
from django.conf.urls import url, include urlpatterns = [ url(r'^', include('snippets.urls')), ]
注意:咱們的視圖有某些問題是尚未作妥善的處理,好比發送的json格式不正確,或是調用視圖沒有的方法,那麼咱們就會返回一個500「服務器錯誤」的消息。