1. 程式人生 > >定義序列化器之關聯屬性(一對多、多對多)

定義序列化器之關聯屬性(一對多、多對多)

定義序列化器,通常是拿模型類的程式碼過來修改一下。但是如果遇到有關聯屬性的時候,應該怎麼寫呢?

假設有兩個模型類,一個是員工,一個是部門。部門與員工是一對多關係。那麼在定義序列器的時候怎麼寫關聯屬性的語句呢?

先把沒有涉及關聯屬性的欄位寫成序列化器:

from rest_framework import serializers


class DepartmentSerializer(serializers.Serializer):
    """部門序列化器類"""
    id = serializers.IntegerField(read_only=True)
    name 
= serializers.CharField(max_length=20) create_date = serializers.DateField()class EmployeeSerializer(serializers.Serializer): """員工序列化器""" choices_gender = ( (0, ''), (1, ''), ) name = serializers.CharField(max_length=20) age = serializers.IntegerField() gender
= serializers.ChoiceField(default=0, choices=choices_gender) salary = serializers.DecimalField(max_digits=8, decimal_places=2) comment = serializers.CharField(max_length=300) hire_date = serializers.DateField()

 

  • 一對多關係中,多的那方的序列化器關聯屬性的寫法:

如果我要對員工物件序列化時有這樣的效果:

# 第一種效果
{ "name": "趙小一",
    ..., "department": 1, # 第1種:PrimaryKeyRelatedField }

# 第二種效果
{ "name": "趙小一",
    ..., "department": "研發部", # 第2種:StringRelatedField }

# 第三種效果 { "name": "趙小一",
    ..., "department": { # 第3種:DepartmentSerializer "id": 1, "name": "研發部", "create_date": "2018-1-1" } }

 

員工序列化器的定義如下:

class EmployeeSerializer(serializers.Serializer):
    """員工序列化器"""

    choices_gender = (
        (0, ''),
        (1, ''),
    )

    name = serializers.CharField(max_length=20)
    age = serializers.IntegerField()
    gender = serializers.ChoiceField(default=0, choices=choices_gender)
    salary = serializers.DecimalField(max_digits=8, decimal_places=2)
    comment = serializers.CharField(max_length=300)
    hire_date = serializers.DateField()
    # 定義序列化器時關聯屬性的設定
    # 1.1 返回關聯屬性的主鍵,設定屬性為read_only=True表示修改時,即使傳過來的員工資訊有部門的id,也不做修改,保留原始的值!
    department = serializers.PrimaryKeyRelatedField(read_only=True)
    # 1.2 返回關聯屬性的主鍵,設定屬性為查詢集,表示修改時,當你要修改部門時,如果查詢集有,可以修改,如果沒有,不可以修改!
    department = serializers.PrimaryKeyRelatedField(queryset=Department.objects.all())
    # 2 返回關聯屬性的類的__str__方法的值。如果我們想要返回部門的名稱,可以在model裡面增加__str__方法返回部門名稱
    department = serializers.StringRelatedField()
    # 3 返回關聯屬性的所有屬性值時,可以這樣寫:
    department = DepartmentSerializer()

 

  • 一對多關係中,一的那方的序列化器關聯屬性的寫法:(多對多關係的兩邊都可以這樣寫

部門序列化器的定義如下:

class DepartmentSerializer(serializers.Serializer):
    """部門序列化器類"""
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=20)
    create_date = serializers.DateField()
    is_delete = serializers.BooleanField(default=False)
    # 返回關聯屬性的主鍵,因為有多個,所以必須加上many=True
    employee_set = serializers.PrimaryKeyRelatedField(read_only=True,many=True)
    # 返回關聯屬性的類的__str__方法的值。如果我們想要返回員工的名字,可以在model裡面增加__str__方法返回員工的名字。
    employee_set = serializers.StringRelatedField(many=True)
    # 返回關聯屬性的所有屬性值
    employee_set = EmpSerializer(many=True)

注意:因為一的這方序列化時會出現多條關聯屬性,所以必須加上many=True。

 

  • 一個小小的坑

如果在一個檔案中,定義了員工和部門的序列化器,並且,兩個序列化器都返回關聯屬性的所有屬性值時:

部門序列化器有這句語句:

employee = EmployeeSerializer(many = True)

員工序列化器有這句語句:

department = DepartmentSerializer()

此時會出現相互引用的情況,導致出錯!

解決辦法:

在部門序列化器前再加多一個員工序列化器,並且把department = DepartmentSerializer()刪掉!