Django 學習之Django Rest Framework_序列化器_Serializer

 

做用:python

1.序列化,序列化器會把模型對象轉換成字典,通過response之後變成json字符串。mysql

2.反序列化,把客戶端發送過來的數據,通過request之後變成字典,序列化器能夠把字典轉成模型。sql

3.反序列化,完成數據校驗功能。數據庫

一.定義序列化器

Django REST framework中的Serializer使用類來定義,須繼承自rest_framework.serializers.Serializer。django

接下來,爲了方便演示序列化器的使用,咱們先建立一個新的子應用sersjson

python manage.py startapp sers後端

咱們已有了一個數據庫模型類studentsapi

verbose_name="姓名" 將字段用在後端xadmin中實現中文顯示
from django.db import models

# Create your models here.
class Student(models.Model):
    # 模型字段
    name = models.CharField(max_length=100,verbose_name="姓名",help_text="提示文本:帳號不能爲空!")
    sex = models.BooleanField(default=True,verbose_name="性別")
    age = models.IntegerField(verbose_name="年齡")
    class_null = models.CharField(max_length=5,verbose_name="班級編號")
    description = models.TextField(verbose_name="個性簽名")

    class Meta:
        db_table="tb_student"
        verbose_name = "學生"
        verbose_name_plural = verbose_name
models.py

咱們想爲這個模型類提供一個序列化器,在sers下新建一個serializers.py能夠定義以下:瀏覽器

from rest_framework import serializers

# 聲明序列化器,全部的序列化器都要直接或者間接繼承於 Serializer
# 其中,ModelSerializer是Serializer的子類,ModelSerializer在Serializer的基礎上進行了代碼簡化
class StudentSerializer(serializers.Serializer):
    """學生信息序列化器"""
    # 1. 須要進行數據轉換的字段
    id = serializers.IntegerField()
    name = serializers.CharField()
    age = serializers.IntegerField()
    sex = serializers.BooleanField()
    description = serializers.CharField()

    # 2. 若是序列化器集成的是ModelSerializer,則須要聲明調用的模型信息

    # 3. 驗證代碼

    # 4. 編寫添加和更新模型的代碼
serializers.py

還須要註冊新建的sersrestful

'sers.apps.SersConfig',

注意:serializer不是隻能爲數據庫模型類定義,也能夠爲非數據庫模型類的數據定義。serializer是獨立於數據庫以外的存在。

將__init__.py 下的pymysql從students應用剪切到項目下的__init__.py文件下。

二.建立Serializer對象

定義好Serializer類後,就能夠建立Serializer對象了。

Serializer的構造方法爲:

Serializer(instance=None, data=empty, **kwarg)

說明:

1)用於序列化時,將模型類對象傳入instance參數

2)用於反序列化時,將要被反序列化的數據傳入data參數

3)除了instance和data參數外,在構造Serializer對象時,還可經過context參數額外添加數據,如

serializer = AccountSerializer(account, context={'request': request})

經過context參數附加的數據,能夠經過Serializer對象的context屬性獲取。

1. 使用序列化器的時候必定要注意,序列化器聲明瞭之後,不會自動執行,須要咱們在視圖中進行調用才能夠。

2. 序列化器沒法直接接收數據,須要咱們在視圖中建立序列化器對象時把使用的數據傳遞過來。

3. 序列化器的字段聲明相似於咱們前面使用過的表單系統。

4. 開發restful api時,序列化器會幫咱們把模型數據轉換成字典.

5. drf提供的視圖會幫咱們把字典轉換成json,或者把客戶端發送過來的數據轉換字典.

 三.序列化器的使用(主要)

1.序列化

總路由中的urls.py:

from django.contrib import admin
from django.urls import path, include
 
urlpatterns = [
    path('admin/', admin.site.urls),
    path('drf/', include("students.urls")),
    path('ser/', include("ser.urls")),
]
總的urls.py

sers應用下的urls.py文件:

序列化的只包含一條數據的狀況下:

sers應用下的urls.py文件:

from django.urls import path, re_path
from . import views
 
urlpatterns = [
    re_path(r"^student/(?P<pk>\d+)/$", views.Student1View.as_view()),
] 
urls.py

sers應用下的views.py文件:

from django.http import JsonResponse
from django.views import View
from students.models import Student
from .serializers import StudentSerializer
 
 
class Student1View(View):
    """使用序列化器進行數據的序列化操做"""
    """序列化器轉換一條數據[模型轉換成字典]"""
    def get(self, request, pk):
        # 接收客戶端傳過來的參數,進行過濾查詢,先查出學生對象
        student = Student.objects.get(pk=pk)
        # 轉換數據類型
        # 1.實例化序列化器類
        """
            StudentSerializer(instance=模型對象或者模型列表,客戶端提交的數據,額外要傳遞到序列化器中使用的數據)
        """
        serializer = StudentSerializer(instance=student)
 
        # 2.查看序列化器的轉換結果
        print(serializer.data)
        return JsonResponse(serializer.data)
views.py

效果圖以下:

多條數據的查詢集QuerySet狀況

若是要被序列化的是包含多條數據的查詢集QuerySet,能夠經過添加many=True參數補充說明。代碼以下:

sers應用下的urls.py文件改成:

from django.urls import path, re_path
from . import views
 
urlpatterns = [
    path("students/", views.Student2View.as_view()),
    re_path(r"^student/(?P<pk>\d+)/$", views.Student1View.as_view()),
]
urls.py

最後sers應用下的views.py

from django.shortcuts import render

# Create your views here.
from django.http import JsonResponse
from django.views import View
from students.models import Student
from .serializers import StudentSerializer


class Student1View(View):
    """使用序列化器進行數據的序列化操做"""
    """序列化器轉換一條數據[模型轉換成字典]"""

    def get(self, request, pk):
        # 接收客戶端傳過來的參數,進行過濾查詢,先查出學生對象
        student = Student.objects.get(pk=pk)
        # 轉換數據類型
        # 1.實例化序列化器類
        """
            StudentSerializer(instance=模型對象或者模型列表,客戶端提交的數據,額外要傳遞到序列化器中使用的數據)
        """
        serializer = StudentSerializer(instance=student)

        # 2.查看序列化器的轉換結果
        print(serializer.data)
        return JsonResponse(serializer.data)


class Student2View(View):
    """序列化器轉換多條數據[模型轉換成字典]"""

    def get(self, request):
        student_list = Student.objects.all()
        print(student_list)
        # 序列化器轉換多個數據
        # many=True 表示本次序列化器轉換若是有多個模型對象列參數,則必須聲明 Many=True
        serializer = StudentSerializer(instance=student_list, many=True)

        print(serializer.data)
        return JsonResponse(serializer.data, safe=False)
views.py

最後效果圖爲:(下圖此效果爲搜狐瀏覽器,其餘瀏覽器的數據並無那麼整齊)

並且依然能夠實現一條數據數據的狀況。

 2.1反序列化-數據校驗

使用序列化器進行反序列化時,須要對數據進行驗證後,才能獲取驗證成功的數據或保存成模型類對象。

在獲取反序列化的數據前,必須調用is_valid()方法進行驗證,驗證成功返回True,不然返回False

驗證失敗,能夠經過序列化器對象的errors屬性獲取錯誤信息,返回字典,包含了字段和字段的錯誤。is_valid()方法還能夠在驗證失敗時拋出異常serializers.ValidationError,能夠經過傳遞raise_exception=True參數開啓。

驗證成功,能夠經過序列化器對象的validated_data屬性獲取數據。

  在定義序列化器時,指明每一個字段的序列化類型和選項參數,自己就是一種驗證行爲。

sers應用下的urls.py文件:

urlpatterns = [
    path("students/", views.Student2View.as_view()),
    re_path(r"^student/(?P<pk>\d+)/$", views.Student1View.as_view()),
    # 對數據提交時,進行校驗
    path('student3/', views.Student3View.as_view()),
]
urls.py

sers應用下的serializers.py文件:

"""
  在drf中,對於客戶端提供的數據,每每須要驗證數據的有效性,這部分代碼是寫在序列化器中的。
  在序列化器中,已經提供三個地方給咱們針對客戶端提交的數據進行驗證。
  1. 內置選項,字段聲明的小圓括號中,以選項存在做爲驗證提交
  2. 自定義方法,在序列化器中做爲對象方法來提供驗證[ 這部分驗證的方法,必須以"validate_<字段>" 或者 "validate" 做爲方法名 ]
  3. 自定義函數,在序列化器外部,提早聲明一個驗證代碼,而後在字段聲明的小圓括號中,經過 "validators=[驗證函數1,驗證函數2...]"
"""
from rest_framework import serializers
from students.models import Student
# 自定義函數
def check_user(data):
    if data == "teacher":
        raise serializers.ValidationError("用戶名不能爲teacher")
    return data


class Student3Serializer(serializers.Serializer):
    # 校驗的第一種方式(內置選項)          validators=[check_user]
    name = serializers.CharField(max_length=10, min_length=4, validators=[check_user])
    age = serializers.IntegerField(max_value=150, min_value=1)
    sex = serializers.BooleanField(required=True)  # 默認爲True
    description = serializers.CharField()

    # 3. 可選[ 用於對客戶端提交的數據進行驗證 ]
    # 第三步,進行數據校驗
    # 校驗第二種方式(自定義方法)
    # 對單個字段進行校驗
    def validate_name(self, data):
        if data == "root":
            raise serializers.ValidationError("用戶不能爲root")
        return data

    def validate_age(self, data):
        if data > 50:
            raise serializers.ValidationError("此歲數已經打破學生年齡記錄")
        return data

    # 對多個字段進行校驗
    def validate(self, attrs):
        name = attrs.get('name')
        age = attrs.get('age')

        if name == 'bili' and age == 45:
            raise serializers.ValidationError("這是校長的信息,輸錯了吧")
        return attrs
serializers.py

sers應用下的views.py文件:

from sers.serializers import Student3Serializer
import json

class Student3View(View):
    #  反序列化之數據校驗
    def post(self, request):
        # 對數據進行解碼
        data = request.body.decode()
        # 對數據(用戶提交的數據)進行反序列化
        data_dict = json.loads(data)
        # 調用序列化器進行實例化
        serializer = Student3Serializer(data=data_dict)
        # 進行校驗
        # is_valid在執行的時候,會自動前後調用 字段的內置選項,自定義驗證方法,自定義驗證函數
        # 調用序列化器中寫好的驗證代碼
        # 驗證結果
        # raise_exception=True 拋出驗證錯誤信息,並阻止代碼繼續日後運行
        serializer.is_valid(raise_exception=True)

        # 獲取錯誤信息
        print(serializer.errors)

        # 獲取合法的數據信息
        print(serializer.validated_data)

        return HttpResponse("OK")
        # return JsonResponse(serializer.validated_data)
views.py

運行程序並用Post進行測試:

測試一:

正常數據測試:

測試二:name不符合4個字符的內置規定

測試三:單個字段不符合

測試四:多個字段效驗不符合

測試五:自定義函數效驗不符合

2.2反序列化-保存數據

前面的驗證數據成功後,咱們可使用序列化器來完成數據反序列化的過程.這個過程能夠把數據轉成模型類對象

能夠經過在序列化器中實現create()update()兩個方法來實現

sers應用下serializers.py文件:

 

from rest_framework import serializers
from students.models import Student

class Student3Serializer(serializers.Serializer):
    # 校驗的第一種方式(內置選項)
    name = serializers.CharField(max_length=10, min_length=4, validators=[check_user])
    age = serializers.IntegerField(max_value=150, min_value=1)
    sex = serializers.BooleanField(required=True)  # 默認爲True
    description = serializers.CharField()

    # 3. 可選[ 用於對客戶端提交的數據進行驗證 ]
    # 第三步,進行數據校驗
    # 校驗第二種方式(自定義方法)
    # 對單個字段進行校驗
    def validate_name(self, data):
        if data == "root":
            raise serializers.ValidationError("用戶不能爲root")
        return data

    def validate_age(self, data):
        if data > 50:
            raise serializers.ValidationError("此歲數已經打破學生年齡記錄")
        return data

    # 對多個字段進行校驗
    def validate(self, attrs):
        name = attrs.get('name')
        age = attrs.get('age')

        if name == 'bili' and age == 45:
            raise serializers.ValidationError("這是校長的信息,輸錯了吧")
        return attrs

    # 第四步,進行持久化處理(create 和update)
    def create(self, validated_data):
        # 接受客戶端提交的新數據
        name = validated_data.get('name')
        age = validated_data.get('age')
        sex = validated_data.get('sex')
        description = validated_data.get('description')

        instance = Student.objects.create(name=name, age=age, sex=sex, description=description)
    # instance = Student.objects.create(**validated_data)

        print("序列號器的create方法", instance)

        return instance

    def update(self, instance, validated_data):
        # 用於在反序列化中對於驗證完成的數據進行保存更新
        name = validated_data.get('name')
        age = validated_data.get('age')
        sex = validated_data.get('sex')
        description = validated_data.get('description')

        # 更新數據
        instance.name = name
        instance.age = age
        instance.sex = sex
        instance.description = description

        # 同步數據到數據庫
        instance.save()

        return instance
serializers.py

 

實現了上述兩個方法後,在反序列化數據的時候,就能夠經過save()方法返回一個數據對象實例了

sers應用下views.py文件

from sers.serializers import Student3Serializer
import json

class Student3View(View):
    #  反序列化之數據校驗
    def post(self, request):
        # 對數據進行解碼
        data = request.body.decode()
        # 對數據(用戶提交的數據)進行反序列化
        data_dict = json.loads(data)
        # 調用序列化器進行實例化
        serializer = Student3Serializer(data=data_dict)
        # 進行校驗
        # is_valid在執行的時候,會自動前後調用 字段的內置選項,自定義驗證方法,自定義驗證函數
        # 調用序列化器中寫好的驗證代碼
        # 驗證結果
        # raise_exception=True 拋出驗證錯誤信息,並阻止代碼繼續日後運行
        serializer.is_valid(raise_exception=True)

        # 獲取錯誤信息
        print(serializer.errors)

        # 獲取合法的數據信息
        print(serializer.validated_data)

        # save 表示讓序列化器開始執行反序列化代碼。create和update的代碼
        serializer.save()

        # return HttpResponse("OK")
        return JsonResponse(serializer.validated_data)
views.py

測試:

post一組正常的數據:

返回新增的數據:

進數據庫,發現數據已經持久化:

若是建立序列化器對象的時候,沒有傳遞instance實例,則調用save()方法的時候,create()被調用,相反,若是傳遞了instance實例,則調用save()方法的時候,update()被調用。

sers應用下views.py文件添加一個類做爲更新數據:

class Student4View(View):
    def put(self, request, pk):
        data = request.body.decode()
        import json
        data_dict = json.loads(data)
        # 經過pk從數據庫中獲得相應的原數據
        student_obj = Student.objects.get(pk=pk)
        print(pk)
        # 有instance參數,調用save方法,就會調用update方法。
        serializer = Student3Serializer(instance=student_obj, data=data_dict)
        # print(serializer)
        serializer.is_valid(raise_exception=True)

        serializer.save()  # 觸發序列器中的update方法

        return JsonResponse(serializer.validated_data)
views.py

sers應用下的urls.py文件:

from django.urls import path, re_path
from . import views

urlpatterns = [

    path("students/", views.Student2View.as_view()),
    re_path(r"^students/(?P<pk>\d+)/$", views.Student1View.as_view()),

    path("student3/", views.Student3View.as_view()),
    # 反序列化階段(update, 執行的請求方式爲put)
    re_path(r'^student4/(?P<pk>\d+)/$', views.Student4View.as_view()),

]
urls.py

3.序列化與反序列化合並使用

開發中每每一個資源的序列化和反序列化階段都是寫在一個序列化器中的

因此咱們能夠把上面的兩個階段合併起來,之後咱們再次寫序列化器,則直接按照如下風格編寫便可。

sers應用下的serializers.py文件內容能夠直接使用反序列化-保存數據中的Student3Serializer類:

sers應用下urls.py文件:

 

from django.urls import path, re_path
from . import views

urlpatterns = [

    path("students/", views.Student2View.as_view()),
    re_path(r"^students/(?P<pk>\d+)/$", views.Student1View.as_view()),

    path("student3/", views.Student3View.as_view()),
    # 反序列化階段(update, 執行的請求方式爲put)
    re_path(r'^student4/(?P<pk>\d+)/$', views.Student4View.as_view()),
    # 一個序列化器同時實現序列化和反序列化
    path('student5/', views.Student5View.as_view()),

]
urls.py

 

在sers應用下views.py文件:

class Student5View(View):
    def get(self, request):
        # 獲取全部數據
        student_list = Student.objects.all()
        serializer = Student3Serializer(instance=student_list, many=True)

        return JsonResponse(serializer.data, safe=False)

    def post(self, request):
        data = request.body.decode()
        data_dict = json.loads(data)
        # 調用序列化器進行實例化
        serializer = Student3Serializer(data=data_dict)
        # 進行校驗
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return JsonResponse(serializer.data)
views.py

4.模型類序列化器

若是咱們想要使用序列化器對應的是Django的模型類,DRF爲咱們提供了ModelSerializer模型類序列化器來幫助咱們快速建立一個Serializer類。

sers應用下serializers.py文件定義模型類序列化器:

from rest_framework import serializers
from students.models import Student

"""
咱們可使用ModelSerializer來完成模型類序列化器的聲明
這種基於ModelSerializer聲明序列化器的方式有三個優點:
1. 能夠直接經過聲明當前序列化器中指定的模型中把字段聲明引用過來(就是若是都不在加限制字段條件,默認的會是models.py的內容)
2. ModelSerializer是繼承了Serializer的全部功能和方法,同時還編寫update和create
3. 模型中同一個字段中關於驗證的選項,也會被引用到序列化器中一併做爲選項參與驗證
"""


class StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        # fields = "__all__"  # 表示引用全部字段
        fields = ["id", "name", "age", "description", "is_18"]  # is_18 爲自定製字段,須要在models裏自定義方法。
        # exclude = ["age"]  # 使用exclude能夠明確排除掉哪些字段, 注意不能和fields同時使用。
        # 傳遞額外的參數,爲ModelSerializer添加或修改原有的選項參數
        extra_kwargs = {
            "name": {"max_length": 10, "min_length": 4, "validators": [check_user]},
            "age": {"max_value": 150, "min_value": 0},
        }

    def validate_name(self, data):
        if data == "root":
            raise serializers.ValidationError("用戶名不能爲root!")
        return data

    def validate(self, attrs):
        name = attrs.get('name')
        age = attrs.get('age')

        if name == "alex" and age == 22:
            raise serializers.ValidationError("alex在22時的故事。。。")

        return attrs
serializers.py

sers應用下的urls.py文件:

from django.urls import path, re_path
from . import views

urlpatterns = [

    path("students/", views.Student2View.as_view()),
    re_path(r"^students/(?P<pk>\d+)/$", views.Student1View.as_view()),

    path("student3/", views.Student3View.as_view()),
    # 反序列化階段(update, 執行的請求方式爲put)
    re_path(r'^student4/(?P<pk>\d+)/$', views.Student4View.as_view()),
    # 一個序列化器同時實現序列化和反序列化
    path('student5/', views.Student5View.as_view()),
    # 使用模型類序列化器
    path('student6/', views.Student6View.as_view()),

]
urls.py

sers應用下views.py文件:

from sers.serializers import StudentModelSerializer


class Student6View(View):
    # 若是是get方法請求數據
    def get(self, request):
        # 獲取全部數據
        student_list = Student.objects.all()

        serializer = StudentModelSerializer(instance=student_list, many=True)

        return JsonResponse(serializer.data, safe=False)

    #  若是是post方法新增數據
    def post(self, request):
        data = request.body.decode()
        data_dict = json.loads(data)

        serializer = StudentModelSerializer(data=data_dict)

        serializer.is_valid(raise_exception=True)

        serializer.save()

        return JsonResponse(serializer.data)
views.py

原來model.py的內容改成:(在序列化器不對數據再限制的時候,會觸發模型的限制條件)

 

from django.db import models


# Create your models here.
class Student(models.Model):
    # 模型字段
    name = models.CharField(max_length=100, verbose_name="姓名")
    sex = models.BooleanField(default=1, verbose_name="性別")
    age = models.IntegerField(verbose_name="年齡")
    class_null = models.CharField(max_length=5, verbose_name="班級編號")
    description = models.TextField(max_length=1000, verbose_name="個性簽名")

    class Meta:
        db_table = "tb_student"
        verbose_name = "學生"
        verbose_name_plural = verbose_name

    def is_18(self):
        return "big!" if self.age >=18 else "small!"
models.py

 

測試一:get請求數據

測試二:post提交數據

 

返回

數據庫新增了一條數據:

相關文章
相關標籤/搜索