drf Serializer基本使用

雲崖先生發表於2020-10-24

drf序列化

   在前後端不分離的專案中,可以使用Django自帶的forms元件進行資料驗證,也可以使用Django自帶的序列化元件對模型表資料進行序列化。

   那麼在前後端分離的專案中,drf也提供了資料驗證與序列化,相比於Django原生的序列化它更加強大與易用。

準備工作

註冊drf

   首先第一步,我們需要在專案全域性資料夾中註冊drf

INSTALLED_APPS = [
    'app01.apps.App01Config',
    'rest_framework', # 註冊drf
]

模型表

   下面是專案中的模型表。

   學生和班級是一對多

   班級和老師是多對多

   班級和班主任是一對一

from django.db import models

# Create your models here.


class Student(models.Model):
    student_id = models.AutoField(primary_key=True, verbose_name="學生編號")
    student_name = models.CharField(max_length=8, verbose_name="學生姓名")
    student_gender = models.BooleanField(
        choices=([0, "male"], [1, "female"]), default=0, verbose_name="學生性別")
    student_class = models.ForeignKey(
        to="Classes", verbose_name="所屬班級", on_delete=models.CASCADE)  # 一個班級多個學生

    def __str__(self):
        return self.student_name

    class Meta:
        db_table = ''
        managed = True
        verbose_name = 'Student'
        verbose_name_plural = 'Students'


class Classes(models.Model):
    class_id = models.AutoField(primary_key=True, verbose_name="班級編號")
    class_name = models.CharField(max_length=8, verbose_name="班級名稱")
    class_teacher = models.OneToOneField(
        to="Teacher", verbose_name="班主任", on_delete=models.CASCADE)  # 一個班級只有一個班主任

    def __str__(self):
        return self.class_name

    class Meta:
        db_table = ''
        managed = True
        verbose_name = 'Classes'
        verbose_name_plural = 'Classess'


class Teacher(models.Model):
    teacher_id = models.AutoField(primary_key=True, verbose_name="教師編號")
    teacher_name = models.CharField(max_length=8, verbose_name="教師姓名")
    teacher_class = models.ManyToManyField(
        to="Classes", verbose_name="任教班級")  # 一個班級中可有多個老師,一個老師也可以在多個班級中任教

    def __str__(self):
        return self.teacher_name

    class Meta:
        db_table = ''
        managed = True
        verbose_name = 'Teacher'
        verbose_name_plural = 'Teachers'

資料展示

   學生資訊如下:

mysql> select * from app01_student;

+------------+--------------+----------------+------------------+
| student_id | student_name | student_gender | student_class_id |
+------------+--------------+----------------+------------------+
|          1 | 學生1        |              1 |                1 |
|          2 | 學生2        |              1 |                2 |
|          3 | 學生3        |              1 |                2 |
|          4 | 學生4        |              0 |                1 |
+------------+--------------+----------------+------------------+

   教師資訊如下:

mysql> select * from app01_teacher;
+------------+--------------+
| teacher_id | teacher_name |
+------------+--------------+
|          1 | 王老師       |
|          2 | 李老師       |
|          3 | 張老師       |
+------------+--------------+

   班級資訊如下:

mysql> select * from app01_classes;
+----------+--------------+------------------+
| class_id | class_name   | class_teacher_id |
+----------+--------------+------------------+
|        1 | 高一一班     |                1 |
|        2 | 高二一班     |                2 |
+----------+--------------+------------------+

   教師與班級關係如下:

mysql> select * from app01_teacher_teacher_class;

+----+------------+------------+
| id | teacher_id | classes_id |
+----+------------+------------+
|  1 |          1 |          1 |
|  2 |          1 |          2 |
|  3 |          2 |          1 |
|  4 |          2 |          2 |
|  5 |          3 |          1 |
|  6 |          3 |          2 |
+----+------------+------------+

url書寫

   接下來書寫url,以查詢學生模型表為例,為了符合framework規範,所以要有一個有名分組來接收可能獲取/修改/刪除的編號。

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/students/(?P<sid>\d+)?', views.Student.as_view()),
]

# 新增問號,代表可有,可沒有

自定義序列器

   使用自定義序列器。可以更加靈活的使用序列化及反序列化。也是推薦使用的方式。

建立序列類

   序列類的作用如下:

  1. 序列化時,可選擇序列化的模型表欄位
  2. 反序列化時,可選擇對資料驗證的規則,類似於forms元件
from .models import Student
from rest_framework import serializers


class StudentSerializer(serializers.Serializer):
    student_id = serializers.CharField()
    student_name = serializers.CharField()
    student_gender = serializers.BooleanField()
    student_class = serializers.CharField()

進行序列化

   接下來進行序列化,首先要書寫檢視函式。

   由於我們每次都需要返回一個狀態碼,以及內容包裝,所以可以建立一個構建返回內容的類。

   第一步要將序列化類匯入,在進行序列化的時候將需要序列化的資料物件進行傳入。

   當序列化完成後,得到一個序列化物件,它有一個data屬性,是已經序列化完成的一個字典。

   把字典返回,如果不使用rest_framework提供的Response,就得使用JsonResponse

   序列化單個物件,不需要在序列化時指定引數many

   序列化多個物件,需要在序列化時指定引數many

from rest_framework.views import APIView
from rest_framework.views import Request  
from rest_framework.views import Response # 通過Response返回
from app01 import models
from app01.drf_ser import StudentSerializer


class returnData(object):
	# 構建返回的資訊
    def __init__(self):
        self.status = 100  # 100代表成功,200代表失敗
        self.message = None  # 返回的資訊
        self.data = None  # 序列化後的結果

    def get_dict(self):
        return self.__dict__

    @property
    def data(self):
        return self.data

    @data.setter
    def data(self, value):
        self.__dict__["data"] = value


class Student(APIView):
    def get(self, request, sid=None):
        # 初始化返回資訊
        res = returnData()
        if sid:
            # 代表獲取單個
            obj = models.Student.objects.filter(pk=sid).first()
            if obj:
                serializer_result = StudentSerializer(obj)  
                res.data = serializer_result.data
            else:
                res.message = "沒有該學生"
                res.status = 200
            return Response(res.get_dict())

        else:
            # 代表獲取所有
            obj_queryset = models.Student.objects.all()

            if obj_queryset:
                serializer_result = StudentSerializer(
                    obj_queryset, many=True)   # many=True代表獲取多條
                res.data = serializer_result.data

            else:
                res.message = "暫時沒有任何學生"
                res.status = 200
            return Response(res.get_dict())



    def post(self, request, sid):
        # 新增
        pass

    def delete(self, request, sid):
        # 刪除
        pass

    def patch(self, request, sid):
        # 修改
        pass

   序列化時,只關心怎樣將資料返回給頁面。

   所以我們只做GET部分,注意用if判斷來判定是獲取所有,還是獲取單個。

   以下是獲取全部的結果:

# http://127.0.0.1:8000/api/students/

{
    "status": 100,
    "message": null,
    "data": [
        {
            "student_id": "1",
            "student_name": "學生1",
            "student_gender": true,
            "student_class": "高一一班"
        },
        {
            "student_id": "2",
            "student_name": "學生2",
            "student_gender": true,
            "student_class": "高二一班"
        },
        {
            "student_id": "3",
            "student_name": "學生3",
            "student_gender": true,
            "student_class": "高二一班"
        },
        {
            "student_id": "4",
            "student_name": "學生4",
            "student_gender": false,
            "student_class": "高一一班"
        }
    ]
}

   以下是獲取單條的結果:

{
    "status": 100,
    "message": null,
    "data": {
        "student_id": "1",
        "student_name": "學生1",
        "student_gender": true,
        "student_class": "高一一班"
    }
}

   當獲取出錯時,message中就會存在錯誤資訊:

{
    "status": 200,
    "message": "沒有該學生",
    "data": null
}

反序列化引數介紹

   反序列化通常是使用POST/PATCH插入或更新資料時使用,收集到頁面傳遞的資料,進行反序列化後寫入資料庫中。

   當進行反序列化時,可以在序列類中指定一些引數,對將要反序列化寫入模型表的欄位進行檢查。

引數描述
max_length 最大長度
min_lenght 最小長度
allow_blank 是否允許為空
trim_whitespace 是否截斷空白字元
max_value 最小值
min_value 最大值
required 表明該欄位在反序列化時必須輸入,預設True
default 反序列化時使用的預設值
allow_null 表明該欄位是否允許傳入None,預設False
validators 該欄位使用的驗證器
error_messages 包含錯誤編號與錯誤資訊的字典

   初此之外,還有兩個比較特殊的引數:

引數描述
read_only 表明該欄位僅用於序列化輸出,預設False,如果設定成True,postman中可以看到該欄位,修改時,不需要傳該欄位
write_only 表明該欄位僅用於反序列化輸入,預設False,如果設定成True,postman中看不到該欄位,修改時,該欄位需要傳

反序列化鉤子

   validate_欄位名是區域性鉤子

   validate是全域性鉤子

   如果要在鉤子中丟擲異常,則需要匯入異常模組。

from rest_framework import exceptions
# raise exceptions.ValidationError('異常了')

   如下是區域性鉤子的使用示例,因為頁面提交過來的資料關於一對多中的班級欄位是字串,所以我們需要將字串變為模型表物件,方便後面的建立以及更新。

    def validate_student_class(self, data):
    	# data是提交過來的這一個欄位的資料
        class_obj = Classes.objects.filter(class_name=data).first()
        if not class_obj:
            raise exceptions.ValidationError("班級不存在")
        data = class_obj  # 將字串替換為物件
        return data

   全域性鉤子使用也是一樣。如下,驗證學生名和班級名是否相同,如果相同則丟擲異常

    def validate(self, validate_data):
        student_name = validate_data.get("student_name")
        class_obj = validate_data.get("student_class")  # 由於區域性鉤子中,這裡被替換成了物件,所以我們拿到物件不能直接作比較
        if student_name == class_obj.class_name:
            raise exceptions.ValidationError("學生名不能和班級名相同")
        return validate_data

create&update

   在進行反序列化時,必須在序列類中覆寫create()方法以及update()方法。

   其中create()方法針對的是新增使用者,而update()方法針對的是更新使用者。

   如果不進行覆寫,則會丟擲異常,這是因為作者在原始碼中做了介面約束的設定:

def update(self, instance, validated_data):
	raise NotImplementedError('`update()` must be implemented.')

def create(self, validated_data):
	raise NotImplementedError('`create()` must be implemented.')

反序列化案例

   瞭解了上面反序列化需要注意的事項後,開始書寫檢視函式中的POST/PATCH方法。

   下面是建立一個學生的例子:

def post(self, request):
    # 初始化返回資訊
    res = returnData()
    serializer_result = StudentSerializer(data=request.data)  # 傳入request.data即可。這裡一定要使用關鍵字傳參!!!
    if serializer_result.is_valid():
        # 驗證通過了
        serializer_result.save()  # 儲存序列化例項類
        res.data = serializer_result.data  # 遵循規範,返回新增的資料
    else:
        # 驗證沒通過
        res.status = 200
        res.message = "資料校驗失敗"
        res.data = serializer_result.errors # 新增錯誤資訊
    
    return Response(res.get_dict())

   重寫create()方法並返回:

    def create(self, validated_data):
        instance = Student.objects.create(**validated_data)
        return instance  # 這裡返回的資訊會返回到序列類物件的data屬性中

   下面是修改一個學生的例子:

    def patch(self, request, sid):
        # 初始化返回資訊
        res = returnData()
        obj = models.Student.objects.filter(pk=sid).first()
        if obj:
            serializer_result = StudentSerializer(instance=obj, data=request.data)  # 需要傳入的引數,記錄本身,新的資料
            if serializer_result.is_valid():
                # 驗證通過了
                serializer_result.save()  # 儲存序列化例項類
                res.data = serializer_result.data  # 遵循規範,返回修改的資料
            else:
                # 驗證沒通過
                res.status = 200
                res.message = "資料校驗失敗"
                res.data = serializer_result.errors  # 新增錯誤資訊
        else:
                res.status = 200
                res.message = "使用者不存在"

        return Response(res.get_dict())

   重寫update()方法並返回:

    def update(self, instance, validated_data):
    
        # 對資料做更新後再返回
        # validated_data中取出str的鍵,然後用反射進行設定
        
        for k, v in validated_data.items():
            setattr(instance, k, v)
        instance.save()
        return instance

全部程式碼

   views.py

from rest_framework.views import APIView
from rest_framework.views import Request
from rest_framework.views import Response  # 通過Response返回
from app01 import models
from app01.drf_ser import StudentSerializer  # 匯入自定義序列類


class returnData(object):
    # 構建返回的資訊
    def __init__(self):
        self.status = 100  # 100代表成功,200代表失敗
        self.message = None  # 返回的資訊
        self.data = None  # 序列化後的結果

    def get_dict(self):
        return self.__dict__

    @property
    def data(self):
        return self.data

    @data.setter
    def data(self, value):
        self.__dict__["data"] = value


class Student(APIView):
    def get(self, request, sid=None):
        # 初始化返回資訊
        res = returnData()
        if sid:
            # 代表獲取單個
            obj = models.Student.objects.filter(pk=sid).first()
            if obj:
                serializer_result = StudentSerializer(obj)
                res.data = serializer_result.data
            else:
                res.message = "沒有該學生"
                res.status = 200
            return Response(res.get_dict())

        else:
            # 代表獲取所有
            obj_queryset = models.Student.objects.all()

            if obj_queryset:
                serializer_result = StudentSerializer(
                    obj_queryset, many=True)   # many=True代表獲取多條
                res.data = serializer_result.data

            else:
                res.message = "暫時沒有任何學生"
                res.status = 200
            return Response(res.get_dict())

    def post(self, request):
        # 初始化返回資訊
        res = returnData()
        serializer_result = StudentSerializer(
            data=request.data)  # 傳入request.data即可
        if serializer_result.is_valid():
            # 驗證通過了
            serializer_result.save()  # 儲存序列化例項類
            res.data = serializer_result.data  # 遵循規範,返回新增的資料
        else:
            # 驗證沒通過
            res.status = 200
            res.message = "資料校驗失敗"
            res.data = serializer_result.errors  # 新增錯誤資訊

        return Response(res.get_dict())

    def delete(self, request):
        # 刪除
        pass

    def patch(self, request, sid):
        # 初始化返回資訊
        res = returnData()
        obj = models.Student.objects.filter(pk=sid).first()
        if obj:
            serializer_result = StudentSerializer(instance=obj, data=request.data)  # 需要傳入的引數,記錄本身,新的資料
            if serializer_result.is_valid():
                # 驗證通過了
                serializer_result.save()  # 儲存序列化例項類
                res.data = serializer_result.data  # 遵循規範,返回修改的資料
            else:
                # 驗證沒通過
                res.status = 200
                res.message = "資料校驗失敗"
                res.data = serializer_result.errors  # 新增錯誤資訊
        else:
                res.status = 200
                res.message = "使用者不存在"

        return Response(res.get_dict())

   自定義序列類

from .models import Student
from .models import Classes
from rest_framework import serializers
from rest_framework import exceptions


class StudentSerializer(serializers.Serializer):
    student_id = serializers.CharField(read_only=True)  # 建立/修改時不用傳該欄位,但是頁面可以看見
    # 相反的,如果是wrtie_only則代表頁面看不見,但是你要傳
    student_name = serializers.CharField(max_length=8, min_length=3)
    student_gender = serializers.BooleanField()
    student_class = serializers.CharField()

    def validate_student_class(self, data):
        class_obj = Classes.objects.filter(class_name=data).first()
        if not class_obj:
            raise exceptions.ValidationError("班級不存在")
        data = class_obj  # 將字串替換為物件
        return data

    def validate(self, validate_data):
        student_name = validate_data.get("student_name")
        class_obj = validate_data.get("student_class")
        if student_name == class_obj.class_name:
            raise exceptions.ValidationError("學生名不能和班級名相同")
        return validate_data

    def create(self, validated_data):
        instance = Student.objects.create(**validated_data)
        return instance  # 這裡返回的資訊會返回到序列類物件的data屬性中

    def update(self, instance, validated_data):
        # 對資料做更新後再返回
        # validated_data中取出str的鍵,然後用反射進行設定
        for k, v in validated_data.items():
            setattr(instance, k, v)
        instance.save()
        return instance

模型表序列器

   模型表的序列器定製化比較低,但是使用較為方便。

   能夠非常快速的開發介面。

建立序列類

   建立序列器:

# 模型表序列器
class StudentModelSerializer(serializers.ModelSerializer):
    student_id = serializers.CharField(read_only=True)  # 建立/修改時不用傳該欄位,但是頁面可以看見
    student_name = serializers.CharField(max_length=8, min_length=3)
    student_gender = serializers.BooleanField()
    student_class = serializers.CharField()

    class Meta:
        model = Student  # 對應上models.py中的模型
        fields = '__all__'  # 序列化所有欄位

        # fields=('student_id','student_name') # 只序列化指定的欄位
        # exclude=('student_id',) # 跟fields不能同時都寫,寫誰,就表示排除誰
        # read_only_fields=('student_id',)
        # write_only_fields=('student_class',) # 棄用了,使用extra_kwargs
        # extra_kwargs = {  # 類似於這種形式  student_name=serializers.CharField(max_length=16,min_length=4)
        #    'student_name': {'write_only': True},
        # }

    def validate_student_class(self, data):
        class_obj = Classes.objects.filter(class_name=data).first()
        if not class_obj:
            raise exceptions.ValidationError("班級不存在")
        data = class_obj  # 將字串替換為物件
        return data

    def validate(self, validate_data):
        student_name = validate_data.get("student_name")
        class_obj = validate_data.get("student_class")
        print(class_obj)
        if student_name == class_obj.class_name:
            raise exceptions.ValidationError("學生名不能和班級名相同")
        return validate_data

基本使用

   其他使用一模一樣,注意在反序列化時不需要重寫create()updata()方法了。

   以下是檢視API介面中的程式碼,只需要把原本使用自定義序列器的地方修改成使用模型表序列器即可。

from rest_framework.views import APIView
from rest_framework.views import Request
from rest_framework.views import Response  # 通過Response返回
from app01 import models
# from app01.drf_ser import StudentModelSerializer
from app01.drf_ser import StudentModelSerializer


class returnData(object):
    # 構建返回的資訊
    def __init__(self):
        self.status = 100  # 100代表成功,200代表失敗
        self.message = None  # 返回的資訊
        self.data = None  # 序列化後的結果

    def get_dict(self):
        return self.__dict__

    @property
    def data(self):
        return self.data

    @data.setter
    def data(self, value):
        self.__dict__["data"] = value


class Student(APIView):
    def get(self, request, sid=None):
        # 初始化返回資訊
        res = returnData()
        if sid:
            # 代表獲取單個
            obj = models.Student.objects.filter(pk=sid).first()
            if obj:
                serializer_result = StudentModelSerializer(obj)
                res.data = serializer_result.data
            else:
                res.message = "沒有該學生"
                res.status = 200
            return Response(res.get_dict())

        else:
            # 代表獲取所有
            obj_queryset = models.Student.objects.all()

            if obj_queryset:
                serializer_result = StudentModelSerializer(
                    obj_queryset, many=True)   # many=True代表獲取多條
                res.data = serializer_result.data

            else:
                res.message = "暫時沒有任何學生"
                res.status = 200
            return Response(res.get_dict())

    def post(self, request):
        # 初始化返回資訊
        res = returnData()
        serializer_result = StudentModelSerializer(
            data=request.data)  # 傳入request.data即可
        if serializer_result.is_valid():
            # 驗證通過了
            serializer_result.save()  # 儲存序列化例項類
            res.data = serializer_result.data  # 遵循規範,返回新增的資料
        else:
            # 驗證沒通過
            res.status = 200
            res.message = "資料校驗失敗"
            res.data = serializer_result.errors  # 新增錯誤資訊

        return Response(res.get_dict())

    def delete(self, request):
        # 刪除
        pass

    def patch(self, request, sid):
        # 初始化返回資訊
        res = returnData()
        obj = models.Student.objects.filter(pk=sid).first()
        if obj:
            serializer_result = StudentModelSerializer(instance=obj, data=request.data)  # 需要傳入的引數,記錄本身,新的資料
            if serializer_result.is_valid():
                # 驗證通過了
                serializer_result.save()  # 儲存序列化例項類
                res.data = serializer_result.data  # 遵循規範,返回修改的資料
            else:
                # 驗證沒通過
                res.status = 200
                res.message = "資料校驗失敗"
                res.data = serializer_result.errors  # 新增錯誤資訊
        else:
                res.status = 200
                res.message = "使用者不存在"

        return Response(res.get_dict())

多關係子序列化

source引數

   source引數的使用:

  1. 可以改欄位名字 xxxx=serializers.CharField(source='student_name')
  2. 可以.跨表 cls=serializers.CharField(source='student_class.name') # 相當於 student_student_class__name進行資料獲取
  3. 可以執行方法pub_date=serializers.CharField(source='test') test是Student表模型中的方法(可忽略,這個相當於驗證方法。還不如使用鉤子函式)

   該引數最重要的兩點,source中寫的是什麼,就從哪裡取資料,即展示的就是什麼。當反序列化時,不再按照序列器類的欄位名進行反序列化,而是按照該引數進行反序列化填值。

   看一下,我要讓student_name顯示的不是學生的名字,而是班主任的名字,就用到了第一條和第二條,跨表,顯示資料,可以這樣設定。

class StudentSerializer(serializers.Serializer):
    student_id = serializers.CharField(read_only=True)  # 建立/修改時不用傳該欄位,但是頁面可以看見
    student_name = serializers.CharField(max_length=8, min_length=3,source="student_class.class_teacher.teacher_name")  # 相當於:Student.objects.filter(pk=傳入的id).values_list("student_class__class_teacher__teacher_name")[0][0]
    student_gender = serializers.BooleanField(source="student_gender")
    student_class = serializers.CharField() 

   當進行GET請求後,將會看到下面的結果:

# http://127.0.0.1:8000/api/students/5/

{
    "status": 100,
    "message": null,
    "data": {
        "student_id": "5",
        "student_name": "王老師",  # 所以說,該引數後面寫的是什麼,展示的就是什麼。
        "student_gender": false,
        "student_class": "高一一班"
    }
}

   示例演示,我們通常會將展示的資料名字進行重新命名,區分開與資料庫儲存的欄位名,這樣做更加安全,所以可以進行如下設定:

from .models import Student
from .models import Classes
from rest_framework import serializers
from rest_framework import exceptions


class StudentSerializer(serializers.Serializer):
    sid = serializers.CharField(read_only=True,source="student_id")  # 建立/修改時不用傳該欄位,但是頁面可以看見
    name = serializers.CharField(max_length=8, min_length=3,source="student_name")
    gender = serializers.BooleanField(source="student_gender")
    classes = serializers.CharField(source="student_class")  # source中寫的是什麼,就從哪裡取資料

    def validate_classes(self, data):
    	# data是提交過來的這一個欄位的資料
        class_obj = Classes.objects.filter(class_name=data).first()
        if not class_obj:
            raise exceptions.ValidationError("班級不存在")
        data = class_obj  # 將字串替換為物件
        return data

    def create(self, validated_data):
        instance = Student.objects.create(**validated_data)
        return instance  # 這裡返回的資訊會返回到序列類物件的data屬性中

    def update(self, instance, validated_data):
        # 對資料做更新後再返回
        # validated_data中取出str的鍵,然後用反射進行設定
        for k, v in validated_data.items():
            setattr(instance, k, v)
        instance.save()
        return instance
{
    "status": 100,
    "message": null,
    "data": {
        "sid": "5",
        "name": "修改學生5",
        "gender": false,
        "classes": "高一一班"
    }
}

SerializerMethodField欄位

   它需要有個配套方法,方法名叫get_欄位名,返回值就是要顯示的東西。

   比如,我們想檢視每個學生都有那些老師在教授,就可以使用該引數:

class StudentSerializer(serializers.Serializer):
    sid = serializers.CharField(read_only=True,source="student_id")  # 建立/修改時不用傳該欄位,但是頁面可以看見
    name = serializers.CharField(max_length=8, min_length=3,source="student_name")
    gender = serializers.BooleanField(source="student_gender")
    classes = serializers.CharField(source="student_class")  # 現在,我要讓他顯示的是班級編號,而不再是班級名稱了
    students = serializers.SerializerMethodField()

    def get_students(self,instance):
        teacher_queryset = instance.student_class.teacher_set.values("pk","teacher_name")
        return teacher_queryset

   最後的結果如下:

# http://127.0.0.1:8000/api/students/5/

{
    "status": 100,
    "message": null,
    "data": {
        "sid": "5",
        "name": "修改學生5",
        "gender": false,
        "classes": "高一一班",
        "students": [
            {
                "pk": 1,
                "teacher_name": "王老師"
            },
            {
                "pk": 2,
                "teacher_name": "李老師"
            },
            {
                "pk": 3,
                "teacher_name": "張老師"
            }
        ]
    }
}

相關文章