歡迎訪問我的個人網站:www.comingnext.cn
關於RESTful API
現在,在開發的過程中,我們經常會聽到前后端分離這個技術名詞,顧名思義,就是前台的開發和后台的開發分離開。這個技術方案的實現就是要借助API,API簡單說就是開發人員提供編程接口被其他人調用,他們調用之后會返回數據供其使用。API的類型有多種,但是現在比較主流且實用的就是本文要說的RESTful API,關於RESTful API,可以通過阮大神的這篇文章了解一下:http://www.ruanyifeng.com/blog/2011/09/restful
如果懶得看,那么可以看一下下面的這個關於 RESTful API 的總結:
1.每一個URL代表一種資源
2.客戶端和服務器之間,傳遞這種資源的某種表現層
3.客戶端通過四個HTTP動詞,對服務器端資源進行操作,實現"表現層狀態轉化"。具體為:
GET用來獲取資源,POST用來新建資源(也可以用於更新資源),PUT用來更新資源,DELETE用來刪除資源。
看這個應該能看懂,想要深入的理解需要在開發中慢慢的學習。
這個系列的博客文章,我是邊學邊寫的,所以這里面可能會有一些理解錯誤的,歡迎各位大佬指正~主要目的是為了交流、分享、學習
關於Django編寫RESTful API,用的當然是那個很厲害的Django庫了—— djangorestframework,而且文檔非常詳細,我就是看官方文檔學習的,這一系列的文章也是根據官方文檔來的,所以代碼和思路基本是一樣的,當然這個並不是簡單的翻譯過來而已,我加入了很多自己的理解以及實際操作中可能會遇到的一些情況,包括一些截圖希望能讓你操作起來更快更易懂。
OK,不廢話了,下面進入主題。
搭建開發環境
首先當然是在虛擬環境中使用了,這個不多說,需要用到的包:
pip install django pip install djangorestframework pip install pygments # 用來實現代碼高亮
其他開發環境:
- pycharm 2017
- win 10
- Python 3.5
開始
首先創建一個名為tutorial的工程,然后在這個工程中創建一個snippets的APP:
django-admin.py startproject tutorial
cd tutorial
python manage.py startapp snippets
創建完成之后在tutorial/settings.py中修改一下INSTALLED_APPS,添加兩個APP:
1 INSTALLED_APPS = ( 2 ... 3 'rest_framework', 4 'snippets.apps.SnippetsConfig', # 如果Django<1.9,那么使用snippets代替 5 )
創建模型類
創建一個Snippet模型類,用於儲存代碼段,編寫snippets/models.py:
1 from django.db import models 2 from pygments.lexers import get_all_lexers 3 from pygments.styles import get_all_styles 4 5 LEXERS = [item for item in get_all_lexers() if item[1]] 6 LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS]) # 得到所有的編程語言 7 STYLE_CHOICES = sorted((item, item) for item in get_all_styles()) # 得到所有的配色風格 8 9 10 class Snippet(models.Model): 11 created = models.DateTimeField(auto_now_add=True) 12 title = models.CharField(max_length=100, blank=True, default='') 13 code = models.TextField() 14 linenos = models.BooleanField(default=False) 15 language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100) 16 style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100) 17 18 class Meta: 19 ordering = ('created',)
除了注釋的那里,其他的代碼都很常規,和我們平時Django開發時是一樣的。然后就為這個模型創建並遷移數據(這里只是為了展示,所以使用的數據庫是Django自帶的那個sqlite):
python manage.py makemigrations snippets
python manage.py migrate
創建序列化類
到了這里就開始進入文章標題所講的序列化了。首先解釋一下序列化:在這里可以先簡單的理解為serializer(等下的代碼會引入的一個Django-REST-Framework的序列化庫)把模型實例轉化為json格式然后響應出去,這樣便於客戶端調用時解析使用。
例如一個PostModel,里面有兩個字段分別為title和author,序列化之后就是{'title':'RESTful API','author':'ziv'}這樣的json格式,這樣明顯就更適合各種客戶端的使用人員解析使用。
那么反序列化其實道理差不多,反序列化之后的數據格式更便於后台使用,等下會有例子加深理解。
解釋完序列化,那么接下來就該敲代碼了,在snippets下面創建一個serializers.py,代碼如下:
1 from rest_framework import serializers 2 from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES 3 4 5 class SnippetSerializer(serializers.Serializer): 6 id = serializers.IntegerField(read_only=True) 7 title = serializers.CharField(required=False, allow_blank=True, max_length=100) 8 # 利用字段標志控制序列化器渲染到HTML頁面時的的顯示模板 9 code = serializers.CharField(style={'base_template': 'textarea.html'}) 10 linenos = serializers.BooleanField(required=False) 11 language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python') 12 style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly') 13 14 # 給定經過驗證的數據,創建並返回一個新的 Snippet 實例 15 def create(self, validated_data): 16 return Snippet.objects.create(**validated_data) 17 18 # 給定經過驗證的數據,更新並返回一個已經存在的 Snippet 實例 19 def update(self, instance, validated_data): 20 instance.title = validated_data.get('title', instance.title) 21 instance.code = validated_data.get('code', instance.code) 22 instance.linenos = validated_data.get('linenos', instance.linenos) 23 instance.language = validated_data.get('language', instance.language) 24 instance.style = validated_data.get('style', instance.style) 25 instance.save() 26 return instance
create和update方法定義在調用serializer.save()時如何創建或修改完整的實例。
關於下面這行代碼:
code = serializers.CharField(style={'base_template':'textarea.html'})
暫時需要知道的就是它的功能是控制序列化器渲染到HTML頁面時的的顯示模板,至於為什么要這樣做,是因為這對於控制如何顯示可瀏覽的API特別有用,這將在后面的文章中看到。
使用序列化器
首先進入shell模式:
python manage.py shell
接下來的操作就和學習Django的orm時那樣,創建並保存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()
這個時候查看數據庫就會發現相關的表中已經多了兩行數據,就是我們剛才創建的數據:
也可以繼續在shell中查看:
>>> serializer = SnippetSerializer(snippet) >>> serializer.data {'code': 'print "hello, world"\n', 'title': '', 'linenos': False, 'style' : 'friendly', 'language': 'python', 'id': 2}
將數據渲染成json格式:
>>> content = JSONRenderer().render(serializer.data) >>> content b'{"id":2,"title":"","code":"print \\"hello, world\\"\\n","linenos":false ,"language":"python","style":"friendly"}'
這里已經出現了json格式,也就是說這個json格式的數據就是要展示在某個URL上,大概可以感覺到,等下我們在訪問某個URL時,會返回上面這堆數據供你使用,這其實就完成了一個序列化的過程,也可以看出客戶端的功能雛形。
序列化是為了返回json格式的數據給客戶端查看和使用數據,那么當客戶端需要修改、增加或者刪除數據時,就要把過程反過來了,也就是反序列化,把客戶端提交的json格式的數據反序列化。
下面的代碼把json數據流解析成Python自帶的數據格式,便於我們后台Django的操作:
>>> 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"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]) >>> serializer.save() <Snippet: Snippet object>
這個時候查看數據庫又多了一條數據:
使用 ModelSerializers
在上面的SnippetSerializer類中,我們繼承的是serializers.Serializer類,可以看到SnippetSerializer類中有很多代碼其實是和models.py中的Snippet模型類似一樣的,所以這里我們可以改進一下。就像在Django中提供了Form類和ModelForm類一樣,django-rest-framework為我們提供了Serializer類和ModelSerializer類。利用它可以讓我們的代碼簡潔很多,修改serializers.py:
1 class SnippetSerializer(serializers.ModelSerializer): 2 class Meta: 3 model = Snippet 4 fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
我們可以通過在shell中的打印來檢查序列化器實例中的所有字段:
>>> from snippets.serializers import SnippetSerializer >>> serializer = SnippetSerializer() >>> print(repr(serializer))
打印后出現的效果如下(language非常長,只截取了一部分):
(兩個圖是同一次打印的,太長了分開截圖)
在我們新的SnippetSerializer類中,可以發現和之前的對比代碼少了很多,這里體現了ModelSerializer 類的快捷:
- 自動確定字段
- create和update方法的簡單默認實現
編寫常規的Django視圖
接下來要做的就是使用我們的新的Serializer類編寫一些API視圖。編輯snippets/views.py:
1 from django.http import HttpResponse, JsonResponse 2 from django.views.decorators.csrf import csrf_exempt 3 from rest_framework.renderers import JSONRenderer 4 from rest_framework.parsers import JSONParser 5 from snippets.models import Snippet 6 from snippets.serializers import SnippetSerializer 7 8 9 # Create your views here. 10 @csrf_exempt 11 def snippet_list(request): 12 """ 13 列出所有已經存在的snippet或者創建一個新的snippet 14 """ 15 if request.method == 'GET': 16 snippets = Snippet.objects.all() 17 serializer = SnippetSerializer(snippets, many=True) 18 return JsonResponse(serializer.data, safe=False) 19 20 elif request.method == 'POST': 21 data = JSONParser().parse(request) 22 serializer = SnippetSerializer(data=data) 23 if serializer.is_valid(): 24 serializer.save() 25 return JsonResponse(serializer.data, status=201) 26 return JsonResponse(serializer.errors, status=400) 27 28 29 @csrf_exempt 30 def snippet_detail(request, pk): 31 """ 32 檢索查看、更新或者刪除一個代碼段 33 """ 34 try: 35 snippet = Snippet.objects.get(pk=pk) 36 except Snippet.DoesNotExist: 37 return HttpResponse(status=404) 38 39 if request.method == 'GET': 40 serializer = SnippetSerializer(snippet) 41 return JsonResponse(serializer.data) 42 43 elif request.method == 'PUT': 44 data = JSONParser().parse(request) 45 serializer = SnippetSerializer(snippet, data=data) 46 if serializer.is_valid(): 47 serializer.save() 48 return JsonResponse(serializer.data) 49 return JsonResponse(serializer.errors, status=400) 50 51 elif request.method == 'DELETE': 52 snippet.delete() 53 return HttpResponse(status=204)
上面的代碼都比較好理解,定義了不同http動作時后台不同的操作,在這里也體現了restful API的理念。
需要注意的是記得添加@csrf_exempt修飾器。
為了讓視圖函數被調用,那當然需要設計一下url了,這里的處理和平時Django開發時是一樣的。首先創建snippets/urls.py:
1 from django.conf.urls import url 2 from snippets import views 3 4 urlpatterns = [ 5 url(r'^snippets/$', views.snippet_list), 6 url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail), 7 ]
接着就是tutorial/urls.py,代碼如下:
from django.conf.urls import url, include urlpatterns = [ url(r'^', include('snippets.urls')), ]
對API進行測試
完成了上面那些工作后,就可以開始測試了,退出shell模式並啟動服務器,根據我們剛才設計的url發送請求,需要先安裝httpie模塊:
pip install httpie
然后在命令行窗口訪問,效果如下:

也可以訪問指定id的數據:

當然了,也可以直接在瀏覽器查看,直接輸入那個URL就可以了:

到這里,也就實現了一個功能,當其他人訪問這個URL時返回json格式的數據給他使用。
在下一篇文章將講解處理請求和響應,多謝支持~
本文地址:http://www.cnblogs.com/zivwong/p/7417989.html
作者博客:ziv
歡迎轉載,請在明顯位置給出出處及鏈接