Django編寫RESTful API(一):序列化


歡迎訪問我的個人網站: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()

 

這個時候查看數據庫就會發現相關的表中已經多了兩行數據,就是我們剛才創建的數據: image

也可以繼續在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>

 

這個時候查看數據庫又多了一條數據:

 image


使用 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非常長,只截取了一部分): image

(兩個圖是同一次打印的,太長了分開截圖)

image

在我們新的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

 

然后在命令行窗口訪問,效果如下: 
image
 也可以訪問指定id的數據: 
image
 當然了,也可以直接在瀏覽器查看,直接輸入那個URL就可以了: 
image

到這里,也就實現了一個功能,當其他人訪問這個URL時返回json格式的數據給他使用。

在下一篇文章將講解處理請求和響應,多謝支持~

本文地址:http://www.cnblogs.com/zivwong/p/7417989.html
作者博客:ziv
歡迎轉載,請在明顯位置給出出處及鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM