1. 序列化器概述
在 Django REST Framework(DRF)中,序列化器(Serializer)用于將復雜的數據類型(如模型實例)轉換為 JSON 格式,以便于 API 返回給客戶端。此外,序列化器還可以用于驗證請求數據。
2. 基本的 ModelSerializer 使用
- 在 models.py 中定義了一個 Department 模型,用來表示部門的信息。在這個模型中,我們包括了 full_name 字段(存儲部門的完整名稱),以及 level 字段(表示部門的層級)。
# models.py
from django.db import modelsclass Department(models.Model):# 部門的全名,使用 `CharField` 存儲full_name = models.CharField(max_length=255)# 部門的層級,默認為 0level = models.IntegerField(default=0)def __str__(self):return self.full_name
ModelSerializer
是Serializer
的一個子類,專門用于將 Django 模型實例轉化為 JSON 格式,且支持自動化字段映射。
例子:
from rest_framework import serializers
from .models import Departmentclass DepartmentSerializer(serializers.ModelSerializer):class Meta:model = Departmentfields = '__all__'
這里,DepartmentSerializer
會自動根據 Department
模型的字段生成相應的序列化字段。
3. 使用 SerializerMethodField 動態計算字段
SerializerMethodField
是 DRF 提供的一種特殊字段類型,用于動態計算某個字段的值。你可以定義一個方法,方法名稱是 get_<field_name>
,該方法會自動被調用來計算字段的值。
示例:
假設 Department
模型有一個字段 full_name
,表示部門的全名(例如:“公司-技術-后端”),我們希望計算一個 level
字段,表示該部門的層級。
from rest_framework import serializersclass DepartmentSerializer(serializers.ModelSerializer):# level 字段會動態計算level = serializers.SerializerMethodField(read_only=True)class Meta:model = Departmentfields = '__all__'# 動態計算 level 字段def get_level(self, obj):full_name = obj.full_name# 按照 '-' 分割 full_namefull_name_split = full_name.split('-')# 計算層級:忽略第一個部分(例如“公司”)return len(full_name_split) - 1
在這個示例中:
level
字段是一個SerializerMethodField
,它不會直接從模型中讀取,而是通過get_level
方法動態計算。get_level
方法接收obj
(即當前的Department
實例),根據full_name
字段來計算層級。full_name.split('-')
會將部門的全名拆分為多個部分,然后計算層級。
4. 使用自定義 __init__
方法動態控制字段
有時,我們可能需要根據外部條件來動態修改序列化器中的字段。例如,某些字段可能在某些情況下不需要序列化。我們可以通過重寫 __init__
方法來實現這一點。
示例:
class DepartmentSerializer(serializers.ModelSerializer):level = serializers.SerializerMethodField(read_only=True)def __init__(self, *args, **kwargs):fields = kwargs.pop('fields', [])super().__init__(*args, **kwargs)if fields:# 刪除未指定的字段allowed = set(fields)existing = set(self.fields)for field_name in existing - allowed:self.fields.pop(field_name)def get_level(self, obj):full_name = obj.full_namefull_name_split = full_name.split('-')return len(full_name_split) - 1class Meta:model = Departmentfields = '__all__'depth = 1read_only_fields = ('id',)
在上面的代碼中:
__init__
方法接受一個fields
參數,該參數是一個字段列表,表示要包含的字段。- 如果
fields
參數不為空,它會從已有的字段中刪除未指定的字段,從而控制序列化器返回的字段。
5. 實戰案例:使用 SerializerMethodField 和自定義字段控制
背景:
假設我們要設計一個 API,返回部門的層級結構,并且根據不同的條件返回不同的字段。我們需要動態計算部門的層級,并且能夠根據請求控制返回哪些字段。
模型:
# models.py
from django.db import modelsclass Department(models.Model):full_name = models.CharField(max_length=255)level = models.IntegerField(default=0)def __str__(self):return self.full_name
視圖:
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Department
from .serializers import DepartmentSerializerclass DepartmentView(APIView):def get(self, request):# 假設我們根據參數決定返回哪些字段fields = request.query_params.getlist('fields', [])# 獲取所有部門數據departments = Department.objects.all()# 使用序列化器返回數據serializer = DepartmentSerializer(departments, many=True, fields=fields)return Response(serializer.data, status=status.HTTP_200_OK)
URL 配置:
# urls.py
from django.urls import path
from .views import DepartmentViewurlpatterns = [path('departments/', DepartmentView.as_view(), name='departments-list'),
]
6. 測試:
假設我們有以下部門數據:
full_name | level |
---|---|
公司-技術-后端 | 2 |
公司-財務 | 1 |
公司-人力資源 | 1 |
請求 1:返回所有字段
GET /departments/
返回:
[{"full_name": "公司-技術-后端","level": 2},{"full_name": "公司-財務","level": 1},{"full_name": "公司-人力資源","level": 1}
]
請求 2:僅返回 full_name
和 level
字段
GET /departments/?fields=full_name&fields=level
返回:
[{"full_name": "公司-技術-后端","level": 2},{"full_name": "公司-財務","level": 1},{"full_name": "公司-人力資源","level": 1}
]
7. 總結
SerializerMethodField
:用來動態計算字段的值,可以根據模型實例的內容或請求參數來決定字段的值。get_<field_name>
方法:定義字段的計算邏輯。- 動態字段控制:通過在序列化器的
__init__
方法中動態修改字段來控制序列化器返回哪些字段。 - 實戰案例:通過
fields
參數控制返回字段,并動態計算層級。
這個案例展示了如何在 Django REST Framework 中靈活地使用序列化器來動態計算和控制返回字段,適用于多種 API 場景。