前言
上一篇文章我們講述了序列化,這篇就帶大家一起來實現以下序列化
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
方法,完成校驗通過的數據入庫工作,得到新增的對象