前言
上一篇文章我們講述了序列化,這篇就帶大家一起來實現以下序列化
Serializer
我們使用序列化類Serializer
,我們來看下原始碼結構,這裡推薦使用pycharm
左邊導航欄的Structure
,可以清晰的看到一個檔案的結構,如下圖
我們會發現Serializer
繼承自BaseSerializer
和SerializerMetaclass
,但是Serializer
類中又沒有create
方法和update
方法,所以我們使用的時候必須
自己手動定義這2個方法
準備工作
1.新建一個專案drf_demo
,在專案中新建一個appdrf_app
,在app中新建一個檔案urls.py
,專案結構如下
2.在models.py
檔案中寫入如下程式碼
class Student(models.Model):
SEX_CHOICES = (
(1,'男'),
(2, '女')
)
name = models.CharField(max_length=20, verbose_name='姓名')
age = models.IntegerField(null=True, blank=True, verbose_name='年齡')
sex = models.IntegerField(choices=SEX_CHOICES, default=1, verbose_name='性別')
class Meta:
db_table = "student"
3.在drf_demo.urls.py
和drf_app.urls.py
中分別寫入如下程式碼
# drf_demo.urls.py
urlpatterns = [
path('drf/', include('drf_app.urls')),
]
# drf_app.urls.py
app_name = "drf_app"
urlpatterns = [
path('student/', views.student),
]
4.在settings.py
檔案的MIDDLEWARE
中註釋掉django.middleware.csrf.CsrfViewMiddleware
,並在INSTALLED_APPS
中加入2個app
'rest_framework',
'drf_app'
5.在命令列輸入以下命令,將orm物件對映到資料庫
python manage makemigrations
python manage migrate
6.寫序列化類一般我們都在app專案中新建serializers.py
檔案,接下來可以正式編寫序列化類了
序列化類編寫
# Serializer的建構函式的引數:
# 1. instance:需要傳遞一個orm物件,或者是一個queryset物件,用來將orm轉成json
# 2. data:把需要驗證的資料傳遞給data,用來驗證這些資料是不是符合要求
# 3. many:如果instance是一個queryset物件,那麼就需要設定為True,否則為False
class StudentSerializer(serializers.Serializer):
# 序列化提供給前臺的欄位個數由後臺決定,可以少提供
# 但是提供的資料庫對應的欄位,名字一定要與資料庫欄位相同
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(required=True, max_length=200)
sex = serializers.IntegerField(required=True)
age = serializers.IntegerField(required=True)
def create(self, validated_data):
"""
根據提供的驗證過的資料建立並返回一個新的`Student`例項
"""
return Student.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
根據提供的驗證過的資料更新和返回一個已經存在的`Student`例項。
"""
instance.name = validated_data.get('name', instance.name)
instance.age = validated_data.get('name', instance.age)
instance.sex = validated_data.get('name', instance.sex)
instance.save()
return instance
# 區域性鉤子 validate_要校驗的欄位名(self, 當前要校驗欄位的值)
def validate_name(self, value):
if 'j' in value.lower():
raise exceptions.ValidationError("名字非法")
return value
def validate_sex(self, value):
if not isinstance(value, int):
raise exceptions.ValidationError("只能輸入int型別")
if value != 1 and value != 2 :
raise exceptions.ValidationError("只能輸入男和女")
return value
# 全域性鉤子 validate(self, 系統與區域性鉤子校驗通過的所有資料)
def validate(self, attrs):
age = attrs.get('age')
sex = attrs.get('sex')
if age < 22 and sex == 1:
raise exceptions.ValidationError({"age&sex": "男的必須22週歲以上才能結婚"})
return attrs
我們上面程式碼首先定義了序列化的欄位,欄位中的引數都繼承自Field
類,引數如下
def __init__(self, read_only=False, write_only=False,
required=None, default=empty, initial=empty, source=None,
label=None, help_text=None, style=None,
error_messages=None, validators=None, allow_null=False):
- read_only:當為
True
時表示這個欄位只能讀,只有在返回資料的時候會使用。 - write_only:當為
True
時表示這個欄位只能寫,只有在新增資料或者更新資料的時候會用到。比如我們的賬號密碼,只允許使用者提交,後端是不返回密碼給前臺的 - required:當為
True
時表示這個欄位必填,不填狀態碼會返回400 - default:預設值,沒什麼好說的
- allow_null:當為
True
時,允許該欄位的值為空
之後我們又定義了區域性鉤子,校驗特殊的欄位,比如需求規定,使用者的性別只能輸入男和女,此時你就可以定義一個鉤子,當然drf
自動幫我們做了一些校驗,比如需要的欄位是int
型別,你輸入string
型別,會自動觸發系統的error
,不需要我們額外定義,後面我們會進行測試
接下來我們又定義了一個全域性的鉤子,意思就是針對整個資料進行校驗,最適合的場景比如密碼重複輸入,一般我們註冊的時候,需要輸入2次密碼,第二次用來確認,這個場景就適合用全域性鉤子
編寫完serializers
後,我們最後一步,編寫檢視函式,如下:
def student(request):
# 獲取所有的學生
if request.method == "GET":
# 建立一個queryset物件
stu = Student.objects.all()
# 將物件序列化為dict
stu_data = StudentSerializer(instance=stu, many=True).data
return JsonResponse(status=200, data=stu_data, safe=False)
elif request.method == "POST":
data = JSONParser().parse(request)
serializer = StudentSerializer(data=data)
# 校驗欄位是否符合規範
if serializer.is_valid():
# 符合則儲存到資料庫
serializer.save()
return JsonResponse(data=serializer.data, status=200)
return JsonResponse(serializer.errors, status=400)
測試
測試分為GET
請求和POST
請求
GET請求
我們開啟介面測試工具postman
或者apifox
,這裡以apifox
為例,輸入127.0.0.1:8000/drf/student/
,得到了以下結果
[
{
"id": 1,
"name": "jkc",
"sex": 1,
"age": 18
},
{
"id": 2,
"name": "mary",
"sex": 2,
"age": 20
}
]
說明序列化成功,成功地將資料庫的資料通過json
的格式返回給了前臺
POST請求
同樣開啟介面工具,輸入127.0.0.1:8000/drf/student/
,在body
中選擇json
格式,輸入如下資料
{
"name": "aaaa",
"sex": 2,
"age": 18
}
執行結果如下:
{
"id": 13,
"name": "aaaa",
"sex": 2,
"age": 18
}
說明我們反序列化也成功了,小夥伴們自己實踐時可以檢視資料庫,會多了一條這樣的資料
接下來我們是否能觸發鉤子函式
測試validate_name鉤子
輸入測試資料
{
"name": "jjj",
"sex": 2,
"age": 18
}
返回結果如下:
{
"name": [
"名字非法"
]
}
測試validate_sex鉤子
輸入測試資料
{
"name": "kkk",
"sex": 3,
"age": 18
}
返回結果如下:
{
"sex": [
"只能輸入男和女"
]
}
測試預設的輸入型別錯誤
輸入測試資料
{
"name": "kkk",
"sex": "???",
"age": 18
}
返回結果如下:
{
"sex": [
"請填寫合法的整數值。"
]
}
測試預設的必填項不填
輸入測試資料
{
"name": "kkk"
}
返回結果如下:
{
"sex": [
"該欄位是必填項。"
],
"age": [
"該欄位是必填項。"
]
}
測試全域性鉤子
輸入測試資料
{
"name": "kkk",
"sex": 1,
"age": 18
}
返回結果如下:
{
"age&sex": [
"男的必須22週歲以上才能結婚"
]
}
總結
- 設定必填與選填序列化欄位,設定校驗規則
- 為需要額外校驗的欄位提供區域性鉤子函式,如果該欄位不入庫,且不參與全域性鉤子校驗,可以將值取出校驗
- 為有聯合關係的欄位們提供全域性鉤子函式,如果某些欄位不入庫,可以將值取出校驗
- 重寫
create
方法,完成校驗通過的資料入庫工作,得到新增的物件