Django REST framework API 指南(10):序列化·字段

官方原文連接
本系列文章 github 地址
轉載請註明出處html

Serializer 字段

Form 類中的每一個字段不只負責驗證數據,還負責 「清洗」 它 — 將其規範化爲一致的格式。python

Django 文檔git

序列化字段處理基本數據類型和其餘數據類型(好比自定義的類)之間的轉換。它們還能夠對數據進行驗證,以及從其父對象中檢索和設置值。github


注意: 序列化字段都聲明在 fields.py 中,但按照慣例,應該使用 from rest_framework import serializers ,並用 serializers.<FieldName> 的方式引用。正則表達式


核心參數

每一個序列化字段類的構造函數都須要一些參數。某些字段類須要附加特定於該字段的參數,但應始終接受如下參數:django

read_only

只讀字段包含於輸出 API 中,不該該包含在須要建立或更新操做的輸入 API 中。在序列化類輸入中錯誤的包含 'read_only' 會被忽略。api

將其設置爲 True 可確保在序列化表示時使用該字段,但在反序列化期間建立或更新實例時不使用該字段。bash

默認爲 False數據結構

write_only

將其設置爲 True 以確保在更新或建立實例時可使用該字段,但在序列化表示時不包括該字段。ide

默認爲 False

required

若是在反序列化過程當中沒有該提供字段,一般會出現錯誤。若是在反序列化過程當中不須要此字段,則應該設置爲 false。

將此設置爲 False 還容許在序列化實例時從輸出中省略對象屬性或字典密鑰。若是密鑰不存在,它將不會包含在輸出表示中。

默認爲 True

allow_null

若是把 None 傳遞給序列化字段,一般會引起錯誤。若是 None 應被視爲有效值,則將此關鍵字參數設置爲 True

請注意,將此參數設置爲 True 將意味着序列化輸出的缺省值爲 null,但並不意味着輸入反序列化的缺省值。

默認爲 False

default

若是設置,則會給出默認值,在沒有提供輸入值時,將使用該默認值。若是未設置,則默認行爲是不填充該屬性。

部分更新操做時不該該使用 default。由於有些狀況下,只有傳入數據中提供的字段纔會返回驗證值。

能夠設置爲函數或其餘可調用的對象,在這種狀況下,每次使用該值時都會對其進行調用。被調用時,它將不會收到任何參數。若是可調用對象具備 set_context 方法,那麼在每次將字段實例做爲參數獲取值以前都會調用該方法。這與驗證器的工做方式相同。

在序列化實例時,若是對象屬性或字典關鍵字不存在於實例中,將使用缺省值。

請注意,設置默認值意味着該字段不是必需的。同時包括 defaultrequired 的關鍵字參數都是無效的,會引起錯誤。

source

將用於填充字段的屬性的名稱。能夠是一個只接受 self 參數的方法,如 URLField(source='get_absolute_url'),或者使用點符號來遍歷屬性,如 EmailField(source='user.email')。在使用點符號時,若是在屬性遍歷期間任何對象不存在或爲空,則可能須要提供缺省值。

source ='*' 具備特殊含義,用於表示整個對象應該傳遞到該字段。這對建立嵌套表示或對於須要訪問完整對象以肯定輸出表示的字段很是有用。

默認爲該字段的名稱。

validators

應該應用於傳入字段輸入的驗證函數列表,該列表中的函數應該引起驗證錯誤或僅返回。驗證器函數一般應該引起 serializers.ValidationError ,但 Django 的內置 ValidationError 也支持與 Django 代碼庫或第三方 Django 包中定義的驗證器兼容。

error_messages

一個字典,key 是錯誤代碼, value 是對應的錯誤信息。

label

一個簡短的文本字符串,可用做 HTML 表單字段或其餘描述性元素中字段的名稱。

help_text

一個文本字符串,可用做 HTML 表單字段或其餘描述性元素中字段的描述。

initial

應該用於預填充 HTML 表單字段的值。你可能會傳遞一個可調用對象,就像你對任何常規 Django Field 所作的同樣:

import datetime
from rest_framework import serializers
class ExampleSerializer(serializers.Serializer):
    day = serializers.DateField(initial=datetime.date.today)
複製代碼

style

可用於控制渲染器渲染字段的鍵值對的字典。

這裏有兩個例子是 'input_type''base_template'

# Use <input type="password"> for the input.
password = serializers.CharField(
    style={'input_type': 'password'}
)

# Use a radio input instead of a select input.
color_channel = serializers.ChoiceField(
    choices=['red', 'green', 'blue'],
    style={'base_template': 'radio.html'}
)
複製代碼

Boolean 字段

BooleanField

表示一個 boolean 值。

使用 HTML 編碼表單時須要注意,省略一個 boolean 值被視爲將字段設置爲 False,即便它指定了 default=True 選項。這是由於 HTML 複選框經過省略該值來表示未選中的狀態,因此 REST framework 將省略看做是空的複選框。

請注意,將使用 required=False 選項生成默認的 BooleanField 實例(由於 Django models.BooleanField 始終爲 blank=True)。若是想要更改此行爲,請在序列化類上顯式聲明 BooleanField

對應與 django.db.models.fields.BooleanField.

簽名: BooleanField()

NullBooleanField

表示一個布爾值,它也接受 None 做爲有效值。

對應與 django.db.models.fields.NullBooleanField.

簽名: NullBooleanField()


字符串字段

CharField

表示文本。可使用 max_lengthmin_length 驗證(或限定)文本的長短。

對應與 django.db.models.fields.CharFielddjango.db.models.fields.TextField.

簽名: CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)

  • max_length - 驗證輸入所包含的字符數不超過這個數目。
  • min_length - 驗證輸入所包含的字符數很多於這個數目。
  • allow_blank - 若是設置爲 True,則空字符串應被視爲有效值。若是設置爲 False,那麼空字符串被認爲是無效的並會引起驗證錯誤。默認爲 False
  • trim_whitespace - 若是設置爲 True,則先後空白將被刪除。默認爲 True

allow_null 選項也可用於字符串字段,儘管它相對於 allow_blank 來講不被推薦。同時設置 allow_blank=Trueallow_null=True 是有效的,但這樣作意味着字符串表示容許有兩種不一樣類型的空值,這可能致使數據不一致和微妙的應用程序錯誤。

EmailField

表示文本,將文本驗證爲有效的電子郵件地址。

對應與 django.db.models.fields.EmailField

簽名: EmailField(max_length=None, min_length=None, allow_blank=False)

RegexField

表示文本,用於驗證給定的值是否與某個正則表達式匹配。

對應與 django.forms.fields.RegexField.

簽名: RegexField(regex, max_length=None, min_length=None, allow_blank=False)

強制的 regex 參數能夠是一個字符串,也能夠是一個編譯好的 Python 正則表達式對象。

使用 Django 的 django.core.validators.RegexValidator 進行驗證。

SlugField

一個根據模式 [a-zA-Z0-9_-]+ 驗證輸入的 RegexField

對應與 django.db.models.fields.SlugField.

簽名: SlugField(max_length=50, min_length=None, allow_blank=False)

URLField

一個根據 URL 匹配模式驗證輸入的 RegexField。徹底合格的 URL 格式爲 http://<host>/<path>

對應與 django.db.models.fields.URLField. 使用 Django 的 django.core.validators.URLValidator 進行驗證。

簽名: URLField(max_length=200, min_length=None, allow_blank=False)

UUIDField

確保輸入的字段是有效的 UUID 字符串。to_internal_value 方法將返回一個 uuid.UUID 實例。在輸出時,字段將以規範的連字符格式返回一個字符串,例如:

"de305d54-75b4-431b-adb2-eb6b9e546013"
複製代碼

簽名: UUIDField(format='hex_verbose')

  • format: 肯定 uuid 值的表示形式
    • 'hex_verbose' - 權威的十六進制表示形式,包含連字符: "5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
    • 'hex' - 緊湊的十六進制表示形式, 不包含連字符:"5ce0e9a55ffa654bcee01238041fb31a"
    • 'int' - 128 位整數表示形式:"123456789012312313134124512351145145114"
    • 'urn' - RFC 4122 URN 表示形式: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 修改 format 僅影響表示值。全部格式都被 to_internal_value 接受。

FilePathField

一個其選項僅限於文件系統上某個目錄中的文件名的字段。

對應於 django.forms.fields.FilePathField.

簽名: FilePathField(path, match=None, recursive=False, allow_files=True, allow_folders=False, required=None, **kwargs)

  • path - FilePathField 應該從中選擇的目錄的絕對文件系統路徑。
  • match - 用來過濾文件名的正則表達式,string 類型。
  • recursive - 指定是否應該包含路徑的全部子目錄。默認值是 False
  • allow_files - 是否應該包含指定位置的文件。默認值爲 True。這個參數或 allow_folders 必須是 True。(兩個屬性必須有一個爲 true
  • allow_folders - 是否應該包含指定位置的文件夾。默認值是 False。這個參數或 allow_files 必須是 True。(兩個屬性必須有一個爲 true

IPAddressField

確保輸入是有效的 IPv4 或 IPv6 字符串。

對應於 django.forms.fields.IPAddressFielddjango.forms.fields.GenericIPAddressField.

簽名: IPAddressField(protocol='both', unpack_ipv4=False, **options)

  • protocol 將有效輸入限制爲指定的協議。接受的值是 'both' (默認),'IPv4''IPv6' 。匹配不區分大小寫。
  • unpack_ipv4 解壓 IPv4 映射的地址,如 ::ffff:192.0.2.1。若是啓用此選項,則該地址將解壓到 192.0.2.1。 默認是禁用的。只能在 protocol 設置爲 'both' 時使用。

數字字段

IntegerField

表示整數。

對應於 django.db.models.fields.IntegerField, django.db.models.fields.SmallIntegerField, django.db.models.fields.PositiveIntegerFielddjango.db.models.fields.PositiveSmallIntegerField

簽名: IntegerField(max_value=None, min_value=None)

  • max_value 驗證所提供的數字不大於這個值。
  • min_value 驗證所提供的數字不小於這個值。

FloatField

表示浮點。

對應於 django.db.models.fields.FloatField.

簽名: FloatField(max_value=None, min_value=None)

  • max_value 驗證所提供的數字不大於這個值。
  • min_value 驗證所提供的數字不小於這個值。

DecimalField

表示十進制,由 Python 用 Decimal 實例表示。

對應於 django.db.models.fields.DecimalField.

簽名: DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)

  • max_digits 容許的最大位數。它必須是 None 或大於等於 decimal_places 的整數。
  • decimal_places 小數位數。
  • coerce_to_string 若是應返回字符串值,則設置爲 True ;若是應返回 Decimal 對象,則設置爲 False 。默認值與 COERCE_DECIMAL_TO_STRING settings key 的值相同,除非被覆蓋,不然該值將爲 True。若是序列化對象返回 Decimal 對象,則最終的輸出格式將由渲染器決定。請注意,設置 localize 將強制該值爲 True
  • max_value 驗證所提供的數字不大於這個值。
  • min_value 驗證所提供的數字不小於這個值。
  • localize 設置爲 True 以啓用基於當前語言環境的輸入和輸出本地化。這也會迫使 coerce_to_stringTrue 。默認爲 False 。請注意,若是你在 settings 文件中設置了 USE_L10N=True,則會啓用數據格式化。
  • rounding 設置量化到配置精度時使用的舍入模式。 有效值是 decimal 模塊舍入模式。默認爲 None

用法示例

若要驗證數字到999,精確到 2 位小數,應該使用:

serializers.DecimalField(max_digits=5, decimal_places=2)
複製代碼

用10位小數來驗證數字不超過10億:

serializers.DecimalField(max_digits=19, decimal_places=10)
複製代碼

這個字段還接受一個可選參數,coerce_to_string。若是設置爲 True,則表示將以字符串形式輸出。若是設置爲 False,則表示將保留爲 Decimal 實例,最終表示形式將由渲染器肯定。

若是未設置,則默認設置爲與 COERCE_DECIMAL_TO_STRING setting 相同的值,除非另行設置,不然該值爲 True


日期和時間字段

DateTimeField

表示日期和時間。

對應於 django.db.models.fields.DateTimeField.

簽名: DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)

  • format - 表示輸出格式的字符串。若是未指定,則默認爲與 DATETIME_FORMAT settings key 相同的值,除非設置,不然將爲 'iso-8601'。設置爲格式化字符串則代表 to_representation 返回值應該被強制爲字符串輸出。格式化字符串以下所述。將此值設置爲 None 表示 Python datetime 對象應由 to_representation 返回。在這種狀況下,日期時間編碼將由渲染器肯定。
  • input_formats - 表示可用於解析日期的輸入格式的字符串列表。 若是未指定,則將使用 DATETIME_INPUT_FORMATS 設置,該設置默認爲 ['iso-8601']

DateTimeField 格式化字符串。

格式化字符串能夠是明確指定的 Python strftime 格式,也能夠是使用 ISO 8601 風格 datetime 的特殊字符串 iso-8601 。(例如 '2013-01-29T12:34:56.000000Z'

當一個 None 值被用於格式化 datetime 對象時,to_representation 將返回,最終的輸出表示將由渲染器類決定。

auto_nowauto_now_add 模型字段。

使用 ModelSerializerHyperlinkedModelSerializer 時,請注意,auto_now=Trueauto_now_add=True 的模型字段默認狀況下將使用 read_only=True

若是想覆蓋此行爲,則須要在序列化類中明確聲明 DateTimeField。例如:

class CommentSerializer(serializers.ModelSerializer):
    created = serializers.DateTimeField()

    class Meta:
        model = Comment
複製代碼

DateField

表示日期。

對應於 django.db.models.fields.DateField

簽名: DateField(format=api_settings.DATE_FORMAT, input_formats=None)

  • format - 表示輸出格式的字符串。若是未指定,則默認爲與 DATE_FORMAT settings key 相同的值,除非設置,不然將爲 'iso-8601'。設置爲格式化字符串則代表 to_representation 返回值應該被強制爲字符串輸出。格式化字符串以下所述。將此值設置爲 None 表示 Python date 對象應由 to_representation 返回。在這種狀況下,日期時間編碼將由渲染器肯定。
  • input_formats - 表示可用於解析日期的輸入格式的字符串列表。 若是未指定,則將使用 DATE_INPUT_FORMATS 設置,該設置默認爲 ['iso-8601']

DateField 格式化字符串

格式化字符串能夠是明確指定的 Python strftime 格式,也能夠是使用 ISO 8601 風格 date 的特殊字符串 iso-8601 。(例如 '2013-01-29'

TimeField

表示時間。

對應於 django.db.models.fields.TimeField

簽名: TimeField(format=api_settings.TIME_FORMAT, input_formats=None)

  • format - 表示輸出格式的字符串。若是未指定,則默認爲與 TIME_FORMAT settings key 相同的值,除非設置,不然將爲 'iso-8601'。設置爲格式化字符串則代表 to_representation 返回值應該被強制爲字符串輸出。格式化字符串以下所述。將此值設置爲 None 表示 Python time 對象應由 to_representation 返回。在這種狀況下,日期時間編碼將由渲染器肯定。
  • input_formats - 表示可用於解析日期的輸入格式的字符串列表。 若是未指定,則將使用 TIME_INPUT_FORMATS 設置,該設置默認爲 ['iso-8601']

TimeField 格式化字符串

格式化字符串能夠是明確指定的 Python strftime 格式,也能夠是使用 ISO 8601 風格 time 的特殊字符串 iso-8601 。(例如 '12:34:56.000000'

DurationField

表示持續時間。 對應於 django.db.models.fields.DurationField

這些字段的 validated_data 將包含一個 datetime.timedelta 實例。該表示形式是遵循格式 '[DD] [HH:[MM:]]ss[.uuuuuu]' 的字符串。

簽名: DurationField()


選擇字段

ChoiceField

能夠從一個有限的選擇中接受值的字段。

若是相應的模型字段包含 choices=… 參數,則由 ModelSerializer 自動生成字段。

簽名: ChoiceField(choices)

  • choices - 有效值列表,或 (key, display_name) 元組列表。
  • allow_blank - 若是設置爲 True,則空字符串應被視爲有效值。若是設置爲 False,那麼空字符串被認爲是無效的並會引起驗證錯誤。默認是 False
  • html_cutoff - 若是設置,這將是 HTML 選擇下拉菜單中顯示的選項的最大數量。可用於確保自動生成具備很是大能夠選擇的 ChoiceField,而不會阻止模板的渲染。默認是 None.
  • html_cutoff_text - 指定一個文本指示器,在截斷列表時顯示,好比在 HTML 選擇下拉菜單中已經截斷了最大數量的項目。默認就會顯示 "More than {count} items…"

Allow_blankallow_null 都是 ChoiceField 上的有效選項,但強烈建議只使用一個而不是兩個都用。對於文本選擇,allow_blank 應該是首選,allow_null 應該是數字或其餘非文本選項的首選。

MultipleChoiceField

能夠接受一組零、一個或多個值的字段,從有限的一組選擇中選擇。採起一個必填的參數。 to_internal_value 返回一個包含選定值的 set

簽名: MultipleChoiceField(choices)

  • choices - 有效值列表,或 (key, display_name) 元組列表。
  • allow_blank - 若是設置爲 True,則空字符串應被視爲有效值。若是設置爲 False,那麼空字符串被認爲是無效的並會引起驗證錯誤。默認是 False
  • html_cutoff - 若是設置,這將是 HTML 選擇下拉菜單中顯示的選項的最大數量。可用於確保自動生成具備很是大能夠選擇的 ChoiceField,而不會阻止模板的渲染。默認是 None.
  • html_cutoff_text - 指定一個文本指示器,在截斷列表時顯示,好比在 HTML 選擇下拉菜單中已經截斷了最大數量的項目。默認就會顯示 "More than {count} items…"

Allow_blankallow_null 都是 ChoiceField 上的有效選項,但強烈建議只使用一個而不是兩個都用。對於文本選擇,allow_blank 應該是首選,allow_null 應該是數字或其餘非文本選項的首選。


文件上傳字段

解析和文件上傳。

FileFieldImageField 類只適用於 MultiPartParserFileUploadParser 。大多數解析器,例如, e.g. JSON 不支持文件上傳。 Django 的常規 FILE_UPLOAD_HANDLERS 用於處理上傳的文件。

FileField

表示文件。執行 Django 的標準 FileField 驗證。

對應於 django.forms.fields.FileField.

簽名: FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)

  • max_length - 指定文件名的最大長度。
  • allow_empty_file - 指定是否容許空文件。
  • use_url - 若是設置爲 True,則 URL 字符串值將用於輸出表示。若是設置爲 False,則文件名字符串值將用於輸出表示。默認爲 UPLOADED_FILES_USE_URL settings key 的值,除非另有設置,不然爲 True

ImageField

表示圖片。驗證上傳的文件內容是否匹配已知的圖片格式。

對應於 django.forms.fields.ImageField.

簽名: ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)

  • max_length - 指定文件名的最大長度。
  • allow_empty_file - 指定是否容許空文件。
  • use_url - 若是設置爲 True,則 URL 字符串值將用於輸出表示。若是設置爲 False,則文件名字符串值將用於輸出表示。默認爲 UPLOADED_FILES_USE_URL settings key 的值,除非另有設置,不然爲 True

須要 Pillow 庫或 PIL 庫。 建議使用 Pillow 庫。 由於 PIL 已經再也不維護。


複合字段

ListField

驗證對象列表的字段類。

簽名: ListField(child=<A_FIELD_INSTANCE>, min_length=None, max_length=None)

  • child - 應該用於驗證列表中的對象的字段實例。若是未提供此參數,則列表中的對象將不會被驗證。
  • min_length - 驗證列表中包含的元素數量很多於這個數。
  • max_length - 驗證列表中包含的元素數量不超過這個數。

例如,要驗證整數列表:

scores = serializers.ListField(
   child=serializers.IntegerField(min_value=0, max_value=100)
)
複製代碼

ListField 類還支持一種聲明式風格,容許編寫可重用的列表字段類。

class StringListField(serializers.ListField):
    child = serializers.CharField()
複製代碼

咱們如今能夠在咱們的應用程序中從新使用咱們自定義的 StringListField 類,而無需爲其提供 child 參數。

DictField

驗證對象字典的字段類。DictField 中的鍵老是被假定爲字符串值。

簽名: DictField(child=<A_FIELD_INSTANCE>)

  • child - 應該用於驗證字典中的值的字段實例。若是未提供此參數,則映射中的值將不會被驗證。

例如,要建立一個驗證字符串到字符串映射的字段,能夠這樣寫:

document = DictField(child=CharField())
複製代碼

你也能夠像使用 ListField 同樣使用聲明式風格。例如:

class DocumentField(DictField):
    child = CharField()
複製代碼

JSONField

驗證傳入的數據結構由有效 JSON 基元組成的字段類。在其二進制模式下,它將表示並驗證 JSON 編碼的二進制字符串。

簽名: JSONField(binary)

  • binary - 若是設置爲 True,那麼該字段將輸出並驗證 JSON 編碼的字符串,而不是原始數據結構。默認是 False.

其餘類型的字段

ReadOnlyField

只是簡單地返回字段的值而不進行修改的字段類。

當包含與屬性相關的字段名而不是模型字段時,此字段默認與 ModelSerializer 一塊兒使用。

簽名: ReadOnlyField()

例如,若是 has_expiredAccount 模型中的一個屬性,則如下序列化程序會自動將其生成爲 ReadOnlyField

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'has_expired')
複製代碼

HiddenField

不根據用戶輸入獲取值的字段類,而是從默認值或可調用值中獲取值。

簽名: HiddenField()

例如,要包含始終提供當前時間的字段做爲序列化類驗證數據的一部分,則可使用如下內容:

modified = serializers.HiddenField(default=timezone.now)
複製代碼

若是須要根據某些預先提供的字段值運行某些驗證,則一般只須要 HiddenField 類,而不是將全部這些字段公開給最終用戶。

ModelField

能夠綁定到任意模型字段的通用字段。ModelField 類將序列化/反序列化的任務委託給其關聯的模型字段。該字段可用於爲自定義模型字段建立序列化字段,而無需建立新的自定義序列化字段。

ModelSerializer 使用此字段來對應自定義模型字段類。

簽名: ModelField(model_field=<Django ModelField instance>)

ModelField 類一般用於內部使用,但若是須要,能夠由 API 使用。爲了正確實例化 ModelField,必須傳遞一個附加到實例化模型的字段。例如:ModelField(model_field=MyModel()._meta.get_field('custom_field'))

SerializerMethodField

這是一個只讀字段。它經過調用它所鏈接的序列化類的方法來得到它的值。它可用於將任何類型的數據添加到對象的序列化表示中。

簽名: SerializerMethodField(method_name=None)

  • method_name - 要調用序列化對象的方法的名稱。若是不包含,則默認爲 get_<field_name>.

method_name 參數引用的序列化方法應該接受一個參數(除了 self),這是要序列化的對象。它應該返回你想要包含在對象的序列化表示中的任何內容。例如:

from django.contrib.auth.models import User
from django.utils.timezone import now
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):
    days_since_joined = serializers.SerializerMethodField()

    class Meta:
        model = User

    def get_days_since_joined(self, obj):
        return (now() - obj.date_joined).days
複製代碼

自定義字段

若是你想建立自定義字段,則須要對 Field 進行子類化,而後重寫 .to_representation().to_internal_value() 方法中的一個或兩個。這兩個方法用於在初始數據類型和基本序列化數據類型之間進行轉換。基本數據類型一般是 number,string, boolean, date/time/datetimeNone 。它們也能夠是任何僅包含其餘基本對象的列表或字典。其餘類型可能會支持,但具體取決於你使用的渲染器。

調用 .to_representation() 方法將初始數據類型轉換爲基本的可序列化數據類型。

調用 to_internal_value() 方法將基本數據類型恢復爲其內部 python 表示形式。若是數據無效,此方法應該引起 serializers.ValidationError 異常。

請注意,2.x 版本中存在的 WritableField 類再也不存在。 應此,若是字段須要支持數據輸入,則應該繼承 Field 並覆蓋 to_internal_value()

看幾個栗子

基本的自定義字段

咱們來看一個序列化表明 RGB 顏色值的類的例子:

class Color(object):
    """ A color represented in the RGB colorspace. """
    def __init__(self, red, green, blue):
        assert(red >= 0 and green >= 0 and blue >= 0)
        assert(red < 256 and green < 256 and blue < 256)
        self.red, self.green, self.blue = red, green, blue

class ColorField(serializers.Field):
    """ Color objects are serialized into 'rgb(#, #, #)' notation. """
    def to_representation(self, obj):
        return "rgb(%d, %d, %d)" % (obj.red, obj.green, obj.blue)

    def to_internal_value(self, data):
        data = data.strip('rgb(').rstrip(')')
        red, green, blue = [int(col) for col in data.split(',')]
        return Color(red, green, blue)
複製代碼

默認狀況下,字段值被視爲映射到對象的屬性。若是須要自定義字段值的訪問方式,則須要覆蓋 .get_attribute() 和/或 .get_value()

讓咱們建立一個能夠用來表示被序列化對象的類名的字段:

class ClassNameField(serializers.Field):
    def get_attribute(self, obj):
        # We pass the object instance onto `to_representation`,
        # not just the field attribute.
        return obj

    def to_representation(self, obj):
        """ Serialize the object's class name. """
        return obj.__class__.__name__
複製代碼

拋出驗證錯誤

咱們上面的 ColorField 類目前不執行任何數據驗證。爲了表示無效數據,咱們應該引起一個 serializers.ValidationError,以下所示:

def to_internal_value(self, data):
    if not isinstance(data, six.text_type):
        msg = 'Incorrect type. Expected a string, but got %s'
        raise ValidationError(msg % type(data).__name__)

    if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data):
        raise ValidationError('Incorrect format. Expected `rgb(#,#,#)`.')

    data = data.strip('rgb(').rstrip(')')
    red, green, blue = [int(col) for col in data.split(',')]

    if any([col > 255 or col < 0 for col in (red, green, blue)]):
        raise ValidationError('Value out of range. Must be between 0 and 255.')

    return Color(red, green, blue)
複製代碼

.fail() 方法是引起 ValidationError 的快捷方式,它從 error_messages 字典中接收消息字符串。例如:

default_error_messages = {
    'incorrect_type': 'Incorrect type. Expected a string, but got {input_type}',
    'incorrect_format': 'Incorrect format. Expected `rgb(#,#,#)`.',
    'out_of_range': 'Value out of range. Must be between 0 and 255.'
}

def to_internal_value(self, data):
    if not isinstance(data, six.text_type):
        self.fail('incorrect_type', input_type=type(data).__name__)

    if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data):
        self.fail('incorrect_format')

    data = data.strip('rgb(').rstrip(')')
    red, green, blue = [int(col) for col in data.split(',')]

    if any([col > 255 or col < 0 for col in (red, green, blue)]):
        self.fail('out_of_range')

    return Color(red, green, blue)
複製代碼

這種風格讓你的錯誤信息更清晰,而且與代碼分離,應該是首選。

使用 source='*'

這裏咱們將舉一個具備 x_coordinatey_coordinate 屬性的平面 DataPoint 模型的示例。

class DataPoint(models.Model):
    label = models.CharField(max_length=50)
    x_coordinate = models.SmallIntegerField()
    y_coordinate = models.SmallIntegerField()
複製代碼

使用自定義字段和 source ='*',咱們能夠提供座標對的嵌套表示形式:

class CoordinateField(serializers.Field):

    def to_representation(self, obj):
        ret = {
            "x": obj.x_coordinate,
            "y": obj.y_coordinate
        }
        return ret

    def to_internal_value(self, data):
        ret = {
            "x_coordinate": data["x"],
            "y_coordinate": data["y"],
        }
        return ret


class DataPointSerializer(serializers.ModelSerializer):
    coordinates = CoordinateField(source='*')

    class Meta:
        model = DataPoint
        fields = ['label', 'coordinates']
複製代碼

請注意,此示例不處理驗證。使用 source ='*' 的嵌套序列化類能夠更好地處理座標嵌套,而且帶有兩個 IntegerField 實例,每一個實例都有本身的 source 指向相關字段。

然而,這個例子的關鍵點是:

  • to_representation 傳遞整個 DataPoint 對象, 而且會映射到所需的輸出。
>>> instance = DataPoint(label='Example', x_coordinate=1, y_coordinate=2)
>>> out_serializer = DataPointSerializer(instance)
>>> out_serializer.data
ReturnDict([('label', 'Example'), ('coordinates', {'x': 1, 'y': 2})])
複製代碼
  • 除非咱們的字段是隻讀的,不然 to_internal_value 必須映射回適合更新目標對象的字典。使用 source='*'to_internal_value 的返回將更新根驗證的數據字典,而不是單個鍵。
>>> data = {
...     "label": "Second Example",
...     "coordinates": {
...         "x": 3,
...         "y": 4,
...     }
... }
>>> in_serializer = DataPointSerializer(data=data)
>>> in_serializer.is_valid()
True
>>> in_serializer.validated_data
OrderedDict([('label', 'Second Example'),
             ('y_coordinate', 4),
             ('x_coordinate', 3)])
複製代碼

爲了完整性,咱們再次作一樣的事情,可是使用上面建議的嵌套序列化方法:

class NestedCoordinateSerializer(serializers.Serializer):
    x = serializers.IntegerField(source='x_coordinate')
    y = serializers.IntegerField(source='y_coordinate')


class DataPointSerializer(serializers.ModelSerializer):
    coordinates = NestedCoordinateSerializer(source='*')

    class Meta:
        model = DataPoint
        fields = ['label', 'coordinates']
複製代碼

這裏,咱們在 IntegerField 聲明中處理目標和源屬性對(xx_coordinateyy_coordinate )之間的映射。這是使用了 source ='*'NestedCoordinateSerializer

新的 DataPointSerializer 展示出與自定義字段方法相同的行爲。

序列化:

>>> out_serializer = DataPointSerializer(instance)
>>> out_serializer.data
ReturnDict([('label', 'testing'),
            ('coordinates', OrderedDict([('x', 1), ('y', 2)]))])
複製代碼

反序列化:

>>> in_serializer = DataPointSerializer(data=data)
>>> in_serializer.is_valid()
True
>>> in_serializer.validated_data
OrderedDict([('label', 'still testing'),
             ('x_coordinate', 3),
             ('y_coordinate', 4)])
複製代碼

雖然沒有編寫驗證,可是可使用內置的驗證方式:

>>> invalid_data = {
...     "label": "still testing",
...     "coordinates": {
...         "x": 'a',
...         "y": 'b',
...     }
... }
>>> invalid_serializer = DataPointSerializer(data=invalid_data)
>>> invalid_serializer.is_valid()
False
>>> invalid_serializer.errors
ReturnDict([('coordinates',
             {'x': ['A valid integer is required.'],
              'y': ['A valid integer is required.']})])
複製代碼

出於這個緣由,能夠首先嚐試嵌套序列化類方法。當嵌套序列化類變得不可行或過於複雜時,可使用自定義字段方法。

相關文章
相關標籤/搜索