1.REST Framework概述
Django REST framework是一套基於Django的REST框架,是一個用於構建Web API的功能強大且靈活的工具包。
RESTful 簡述
Representational State Transfer(REST),是一種架構樣式,定義了一套用於創建WEB服務的約束。當前WEB開發趨勢就是前端層出不窮,為了保證一個后台同時適用於多個前端,需要一種統一的機制或API,而RESTful API是目前前后端分離的最佳實踐。
為什么需要前后端分離?
- PC,APP,Pad 等多端適應;
- SPA開發模式流行(Single Page web Application);
- 使得前后端開發職責清楚,提高開發效率高;
- 避免了開發語言和模板語言的高度耦合和開發語言之間的依賴;
RESTful API特點
- 輕量,直接通過HTTP協議,不需要額外的協議;
- 面向資源,每一個URL代表一種資源,具有自解釋性;
- 數據描述簡單,一般通過JSON、xml做數據通信;
- 客戶端根據不同的請求,通過不同的HTTP方法(get、post、delete、put),對服務器資源進行操作。
為什么要使用Django REST 框架而不是Django?
雖然Django中可以通過DTL(Django Template Language)來實現PC端的顯示,但卻無法支持如Android端、ios端。而且Django只能依賴DTL實現PC端的顯示。
要實現一套后台適應多個前端,就必須使用前后端分離技術,因此就要使用RESTful API,而Django REST框架正是基於Django的RESTful API。
2.安裝Django REST Framework
通過如下命令安裝REST 框架:
pip install djangorestframework
如果沒有安裝Python,則需要安裝Python和Django:
sudo apt-get install python3.6 sudo apt-get install python3-pip pip install Django
3.序列化和反序列化
序列化,是指將復雜的QuerySet和Model類型轉換成Python基本數據類型,從而將這些基本數據類型以JSON的形式響應給客戶端。
反序列化則和序列化相反,是指將Http請求中傳入的JSON數據轉換成復雜的數據類型,從而保存在數據庫中。
在REST Framework中,提供了多個用於序列化操作的類,但常用的也就如下兩個:
- Serializer:進行序列化基本的類;
- ModelSerializer:繼承於Serializer,內部實現了通用的序列化邏輯,其中包含了與Model字段對應的字段,可以快速對Model進行序列化。
使用時需要導入對應模塊:
from rest_framework import serializers
接下來我們就分別看看這兩個序列化操作的類。
4.Serializer
Serializer進行序列化的基本格式如下:
from rest_framework import serializers class CommentSerializer(serializers.Serializer): # 指定要序列化的字段 email = serializers.EmailField() content = serializers.CharField(max_length=200) created = serializers.DateTimeField() # 用於反序列化時創建一個Model實例 def create(self, validated_data): return Comment(**validated_data) # 用於反序列化時更新一個Model實例 def update(self, instance, validated_data): # ... instance.email = validated_data.get('email',instance=emial) # ... return instance
接下來我們看看在REST框架中如何對一個Model進行序列化操作。
Step1.創建一個model:
from django.db import models class Student(models.Model): name = models.CharField(max_length=40) age = models.IntegerField() number = models.IntegerField(unique=True) date = models.DateField()
Step2.創建對該Model進行序列化的類:
在app/下創建serializer.py文件
from rest_framework import serializers from .models import Student class StudentSerializer(serializers.Serializer): # 定義要序列化的字段 name = serializers.CharField(read_only=True) age = serializers.IntegerField(read_only=True) number = serializers.IntegerField(read_only=True) date = serializers.DateField(read_only=True) # 在反序列化時,當save()調用時生成一個Student對象 def create(self, validated_data): # 會將生成的實例保存到數據庫 return Student.objects.create(**validated_data) # 在反序列化時,當save()調用時更新Student對象 def update(self, instance, validated_data): instance.name = validated_data.get('name', instance.name) instance.age = validated_data.get('age', instance.age) instance.number = validated_data.get('number', instance.number) instance.date = validated_data.get('date', instance.date) instance.save() #確保保存在數據庫 return instance
這個序列化類中有兩部分:
- 1.定義了要進行序列化的字段;這些字段負責將Python類型轉換成JSON類型,即序列化的過程;
- 2.定義了當serializer.save()時用於生成Model對象的create()和update()方法,這兩方法負責將JSON類型的數據轉換成Python類型的數據,即反序列化的過程。
整個序列化類的實現就這么簡單,接下來我們還需要對這個序列化類進行測試。
測試Serializer有兩種方式,一種是在Django Shell下進行測試,還有一種就是直接創建一個View,通過http請求進行測試,如果掌握了如何創建view,那么請直接在View中進行吧!
Step3.在Django shell下進行序列化測試
使用python manage.py shell進入Django Shell中:
>>> from Students.models import Student # 導入對應module >>> from Students.serializers import StudentSerializer >>> stu = Student(name='zhangsan',age=21,number=1,date='2018-4-23') #創建一個Model實例 >>> stu.save() # 將該實例存入數據庫 >>> serializer = StudentSerializer(stu) #進行序列化 >>> serializer.data # 查看序列化后的結果 {'name': 'zhangsan', 'age': 21, 'number': 1, 'date': '2018-4-23'}
現在將Student實例轉換成了Python中的dict類型,接下來將dict類型轉換為JSON數據:
>>> from rest_framework.renderers import JSONRenderer #JSONRenderer將數據渲染稱JSON格式 >>> content = JSONRenderer().render(serializer.data) >>> content b'{"name":"zhangsan","age":21,"number":1,"date":"2018-4-23"}' >>>
反序列化類似,第一步是將JSON形式數據轉換為流的形式,並將流數據轉化為python本地數據類型:
>>> from django.utils.six import BytesIO >>> from rest_framework.parsers import JSONParser >>> stream = BytesIO(content) # 將JSON數據轉換為流的形式 >>> data = JSONParser().parse(stream) # JSONParser將解析流中的JSON數據,得到Python的類型數據 >>> data {'name': 'zhangsan', 'age': 21, 'number': 1, 'date': '2018-4-23'} # 一個dict類型的數據 >>>
然后將Python本地類型轉換為實例,保存在數據庫中:
>>> serializer = StudentSerializer(data=data) >>> serializer.is_valid() # 驗證是否有效 >>> True >>> serializer.save() # 將保存在數據庫中
該例中是序列化了一個Model對象,如果要序列化由Model.objects.all()返回的一個QuerySet實例,在設置serializer時添加一個參數:
>>> serializer = StudentSerializer(Student.objects.all(), many=True) >>> serializer.data >>>
雖然這種方式略顯麻煩,但對於初學者來說,掌握Django shell還是很有用的。
如果對View相關知識了解,那么可以非常方便的在View中通過Http請求進行驗證,如下是通過GET請求和POST請求用於驗證Serializer:
from rest_framework import views from rest_framework.response import Response from rest_framework import status from . import models from .serializers import StudentSerializer # Create your views here. class show(views.APIView): def get(self, request): """ get方法處理GET請求 """ try: Student = models.Student.objects.all() # Student是一個QuerySet,而不是一個Model對象,因此需要設置many=True serializer = StudentSerializer(Student, many=True) return Response(serializer.data, status=status.HTTP_200_OK) except Student.DoesNotExist: return Response(serializer.data, status=status.HTTP_404_NOT_FOUND) def post(self, request): """ post方法處理POST請求 """ # request.data是請求體中經過解析后的數據 serializer = StudentSerializer(data=request.data) if serializer.is_valid(): # 檢驗是否有效 serializer.save() # 將會調用Serializer中的create(),並保存在數據庫中 # serializer.data是序列化后的原始數據 # rest_framework.status中定義了常見返回值,如404,200... return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) ails/80059024
關於DRF的View相關部分會在之后的文章中詳細總結。
5.Serializer的方法和屬性
1.save()
在調用serializer.save()時,會創建或者更新一個Model實例(調用create()或update()創建),具體根據序列化類的實現而定,如:
# .save() will create a new instance. serializer = StudentSerializer(data=data) # .save() will update the existing `comment` instance. serializer = StudentSerializer(comment, data=data)
2.create()、update()
Serializer中的create()和update()方法用於創建生成一個Model實例,在使用Serializer時,如果要保存反序列化后的實例到數據庫,則必須要實現這兩方法之一,生成的實例則作為save()返回值返回。方法屬性validated_data表示校驗的傳入數據。
3. is_valid()
當反序列化時,在調用Serializer.save()之前必須要使用is_valid()方法進行校驗,如果校驗成功返回True,失敗則返回False,同時會將錯誤信息保存到serializer.errors屬性中。
4.data
serializer.data中保存了序列化后的數據。
5.errors
當serializer.is_valid()進行校驗后,如果校驗失敗,則將錯誤信息保存到serializer.errors屬性中。
6.Serializer中的Field
在定義Model時,我們通過models.<FieldName>獲取了各種不同的字段,作為數據庫中表的一個列。而在Serializer中,也需要通過`serializers.<FieldName>的形式獲取對應Model的字段,用來在JSON數據和Python數據類型之間進行轉換,此外還可以根據Field中傳入的屬性進行校驗、設置默認值。以下對常用Serializer的Field進行整理。
使用時,需要導入所在模塊:
from rest_framework import serializers
1.CharField
對應models.CharField,同時如果指定長度,還會負責校驗文本長度。
max_length:最大長度;
min_length:最小長度;
allow_blank=True:表示允許將空串做為有效值,默認False;
2.EmailField
對應models.EmailField,驗證是否是有效email地址。
3.IntegerField
對應models.IntegerField,代表整數類型
4.FloatField
對應models.FloatField,代表浮點數類型
5.DateTimeField
對應models.DateTimeField,代表時間和日期類型。
format='YYYY-MM-DD hh:mm':指定datetime輸出格式,默認為DATETIME_FORMAT值。
需要注意,如果在 ModelSerializer 和HyperlinkedModelSerializer中如果models.DateTimeField帶有auto_now=True或者auto_add_now=True,則對應的serializers.DateTimeField中將默認使用屬性read_only=True,如果不想使用此行為,需要顯示對該字段進行聲明:
class CommentSerializer(serializers.ModelSerializer): created = serializers.DateTimeField() class Meta: model = Comment
6.FileField
對應models.FileField,代表一個文件,負責文件校驗。
max_length:文件名最大長度;
allow_empty_file:是否允許為空文件;
7.ImageField
對應models.ImageField,代表一個圖片,負責校驗圖片格式是否正確。
max_length:圖片名最大長度;
allow_empty_file:是否允許為空文件;
如果要進行圖片處理,推薦安裝Pillow: pip install Pillow
8.HiddenField
這是serializers中特有的Field,它不根據用戶提交獲取值,而是從默認值或可調用的值中獲取其值。一種常見的使用場景就是在Model中存在user_id作為外鍵,在用戶提交時,不允許提交user_id,但user_id在定義Model時又是必須字段,這種情況下就可以使用HiddenField提供一個默認值:
class LeavingMessageSerializer(serializers.Serializer): user = serializers.HiddenField( default=serializers.CurrentUserDefault() )
6.serializers.Field中的公共參數
所謂公共參數,是指對於所有的serializers.<FieldName>都可以接受的參數。以下是常見的一些公共參數。
1.read_only
read_only=True表示該字段為只讀字段,即對應字段只用於序列化時(輸出),而在反序列化時(創建對象)不使用該字段。默認值為False。
2.write_only
write_only=True表示該字段為只寫字段,和read_only相反,即對應字段只用於更新或創建新的Model時,而在序列化時不使用,即不會輸出給用戶。默認值為False。
3.required
required=False表示對應字段在反序列化時是非必需的。在正常情況下,如果反序列化時缺少字段,則會拋出異常。默認值為True。
4.default
給字段指定一個默認值。需要注意,如果字段設置了default,則隱式地表示該字段已包含required=False,如果同時指定default和required,則會拋出異常。
5.allow_null
allow_null=True表示在序列化時允許None作為有效值。需要注意,如果沒有顯式使用default參數,則當指定allow_null=True時,在序列化過程中將會默認default=None,但並不會在反序列化時也默認。
6.validators
一個應用於傳入字段的驗證函數列表,如果驗證失敗,會引發驗證錯誤,否則直接是返回,用於驗證字段,如:
username = serializers.CharField(max_length=16, required=True, label='用戶名', validators=[validators.UniqueValidator(queryset=User.objects.all(),message='用戶已經存在')])
7.error_message
驗證時錯誤碼和錯誤信息的一個dict,可以指定一些驗證字段時的錯誤信息,如:
mobile= serializers.CharField(max_length=4, required=True, write_only=True, min_length=4, label='電話', error_messages={ 'blank': '請輸入驗證碼', 'required': '該字段必填項', 'max_length': '驗證碼格式錯誤', 'min_length': '驗證碼格式錯誤', })
7.style
一個鍵值對,用於控制字段如何渲染,最常用於對密碼進行密文輸入,如:
password = serializers.CharField(max_length=16, min_length=6, required=True, label='密碼', error_messages={ 'blank': '請輸入密碼', 'required': '該字段必填', 'max_length': '密碼長度不超過16', 'min_length': '密碼長度不小於6', }, style={'input_type': 'password'}, write_only=True)
9.label
一個簡短的文本字串,用來描述該字段。
10.help_text
一個文本字串,可用作HTML表單字段或其他描述性元素中字段的描述。
11.allow_blank
allow_blank=True 可以為空 設置False則不能為空
12.source
source='user.email'(user表的email字段的值給這值) 設置字段值 類似default 通常這個值有外鍵關聯屬性可以用source設置
13.validators
驗證該字段跟 單獨的validate很像
UniqueValidator 單獨唯一
validators=[UniqueValidator(queryset=UserProfile.objects.all())
UniqueTogetherValidator: 多字段聯合唯一,這個時候就不能單獨作用於某個字段,我們在Meta中設置。
validators = [UniqueTogetherValidator(queryset=UserFav.objects.all(),fields=('user', 'course'),message='已經收藏')]
14.error_messages
錯誤消息提示
error_messages={
"min_value": "商品數量不能小於一",
"required": "請選擇購買數量"
})
7.ModelSerializers
ModelSerializers繼承於Serializer,相比其父類,ModelSerializer自動實現了以下三個步驟:
- 1.根據指定的Model自動檢測並生成序列化的字段,不需要提前定義;
- 2.自動為序列化生成校驗器;
- 3.自動實現了create()方法和update()方法。
使用ModelSerializer方式如下:
class StudentSerializer(serializers.ModelSerializer): class Meta: # 指定一個Model,自動檢測序列化的字段 model = StudentSerializer fields = ('id', 'name', 'age', 'birthday')
相比於Serializer,可以說是簡單了不少,當然,有時根據項目要求,可能也會在ModelSerializer中顯示聲明字段,這些在后面總結。
model
該屬性指定一個Model類,ModelSerializer會根據提供的Model類自動檢測出需要序列化的字段。默認情況下,所有Model類中的字段將會映射到ModelSerializer類中相應的字段。
fields
如果不希望對Model中所有的字符進行序列化,可以在fields屬性中顯示指定要進行序列化的字段。