創建環境html
在咱們作任何事情以前,咱們將使用virtualenv建立一個新的虛擬環境。這將確保咱們的包配置與咱們正在開展的任何其餘項目保持良好的隔離。python
virtualenv envsource env/bin/activate
如今咱們在一個virtualenv環境中,咱們能夠安裝咱們的包的要求。git
pip install django pip install djangorestframework pip install pygments # 咱們將使用這個讓代碼突出顯示
注意:要隨時退出virtualenv環境,只需鍵入deactivate。有關更多信息,請參閱virtualenv文檔。github
入門shell
好的,咱們準備好得到編碼。要開始,咱們來建立一個新的項目來處理。數據庫
cd ~ django-admin.py startproject tutorial cd tutorial
一旦完成,咱們能夠建立一個咱們將用來建立一個簡單的Web API的應用程序。django
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。json
好的,咱們準備好了。瀏覽器
建立一個可使用的模型
爲了本教程的目的,咱們將首先建立一個Snippet用於存儲代碼片斷的簡單模型。繼續編輯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, 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',)
咱們還須要爲咱們的代碼段模型建立初始遷移,並首次同步數據庫。
python manage.py makemigrations snippets python manage.py migrate
建立一個Serializer類
咱們須要開始使用Web API的第一件事是提供一種將代碼段實例序列化和反序列化爲表示形式的方式json。咱們能夠經過聲明與Django表單很是類似的序列化器來作到這一點。在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
在咱們進一步瞭解以前,咱們將熟悉使用咱們的新的Serializer類。讓咱們進入Django shell。
python manage.py 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()
咱們如今有幾個片斷實例能夠嘗試。咱們來看看序列化這些實例之一。
### 該代碼是把剛剛保存的數據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與表單的使用狀況。當咱們開始編寫使用咱們的序列化程序的視圖時,類似性將變得更加明顯。
咱們也能夠序列化查詢集而不是模型實例。爲此,咱們只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')])]
使用ModelSerializers
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')
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編寫正常的Django視圖
咱們來看看咱們如何使用咱們的新的Serializer類編寫一些API視圖。目前咱們不會使用任何REST框架的其餘功能,咱們只需將視圖編寫爲常規的Django視圖。
編輯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原本是一個視圖函數,支持監聽全部已有的代碼或者新建的代碼片斷
@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_exemptdef 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), ]
咱們還須要在tutorial/urls.py文件中鏈接根urlconf ,以包含咱們的片斷應用程序的URL。
from django.conf.urls import url, include urlpatterns = [ url(r'^', include('snippets.urls')), ]
值得注意的是,咱們目前尚未正確處理好幾個邊緣案例。若是咱們發送格式錯誤json,或者若是使用視圖不處理的方法發出請求,不過,按照如今這樣作,那麼咱們最終會出現500「服務器錯誤」響應。
測試咱們在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, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly" }]
或者咱們能夠經過引用其id來獲取特定的代碼段:
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。
咱們如今在哪
咱們到目前爲止還行,咱們有一個相似於Django的Forms API和一些常規Django視圖的序列化API。
咱們的API視圖目前沒有特別的特別之處,除了提供json響應外,還有一些錯誤處理咱們仍然想要清理的邊緣狀況,但它是一個運行良好的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