Django(45)drf序列化類的使用(Serializer)


前言

上一篇文章我們講述了序列化,這篇就帶大家一起來實現以下序列化
 

Serializer

我們使用序列化類Serializer,我們來看下源碼結構,這里推薦使用pycharm左邊導航欄的Structure,可以清晰的看到一個文件的結構,如下圖

我們會發現Serializer繼承自BaseSerializerSerializerMetaclass,但是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.pydrf_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周歲以上才能結婚"
    ]
}

 

總結

  1. 設置必填與選填序列化字段,設置校驗規則
  2. 為需要額外校驗的字段提供局部鈎子函數,如果該字段不入庫,且不參與全局鈎子校驗,可以將值取出校驗
  3. 為有聯合關系的字段們提供全局鈎子函數,如果某些字段不入庫,可以將值取出校驗
  4. 重寫create方法,完成校驗通過的數據入庫工作,得到新增的對象


免責聲明!

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



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