Django4.0 遷移-序列化值

2022-03-16 17:50 更新

遷移是包含模型舊定義的 Python 文件,因此,要編寫它們,Django 必須獲取模型的當(dāng)前狀態(tài)并將它們序列化到一個(gè)文件中。

雖然 Django 可以序列化大多數(shù)內(nèi)容,但有些內(nèi)容我們無法序列化為有效的 Python 表示形式——對(duì)于如何將值轉(zhuǎn)換回代碼,沒有 Python 標(biāo)準(zhǔn)(?repr()? 只適用于基本的值,而且沒有指定導(dǎo)入路徑)。

Django 可以序列化以下內(nèi)容:

  • ?int?,?float?,?bool?,?str?,?bytes?,?None?,?NoneType?
  • ?list?,?set?,?tuple?,?dict?,?range?。
  • ?datetime.date?,?datetime.time? 和 ?datetime.datetime? 實(shí)例(包括可識(shí)別時(shí)區(qū)的實(shí)例)
  • ?decimal.Decimal? 實(shí)例
  • ?enum.Enum? 實(shí)例
  • ?uuid.UUID? 實(shí)例
  • ?functools.partial()? 和具有可序列化 ?func?、?args ?和 ?keywords ?值的 ?functools.partialmethod? 實(shí)例。
  • 來自 ?pathlib ?的具體的路徑對(duì)象。 具體路徑被轉(zhuǎn)換為它們的純路徑等價(jià)物,例如 ?pathlib.PosixPath? 到 ?pathlib.PurePosixPath?。
  • ?os.PathLike? 實(shí)例,例如 ?os.DirEntry?,使用 ?os.fspath()? 將其轉(zhuǎn)換為 ?str ?或 ?bytes?。
  • 包含可序列化值的 ?LazyObject ?實(shí)例。
  • 枚舉類型(例如 ?TextChoices ?或 ?IntegerChoices?)實(shí)例。
  • 任何 Django 字段
  • 任何函數(shù)或方法引用(如 ?datetime.datetime.today?)(必須在模塊的頂層范圍內(nèi))
  • 在類主體內(nèi)部使用的未綁定方法
  • 任何類引用(必須在模塊的頂層范圍內(nèi))
  • 具有自定義 ?deconstruct() ?方法的任何東西(見下文)

Django 不能序列化:

  • 嵌套類
  • 任何類實(shí)例(例如 MyClass(4.3, 5.7))
  • 匿名函數(shù)

自定義序列化

你可以通過編寫一個(gè)自定義的序列化器來序列化其他類型。例如,如果 Django 默認(rèn)沒有序列化 ?Decimal ?你可以這樣做:

from decimal import Decimal

from django.db.migrations.serializer import BaseSerializer
from django.db.migrations.writer import MigrationWriter

class DecimalSerializer(BaseSerializer):
    def serialize(self):
        return repr(self.value), {'from decimal import Decimal'}

MigrationWriter.register_serializer(Decimal, DecimalSerializer)

?MigrationWriter.register_serializer()? 的第一個(gè)參數(shù)想要使用序列化器的程序類型或類型的可迭代對(duì)象。
序列化器的 ?serialize()? 方法必須返回一個(gè)字符串,說明該值在遷移中應(yīng)如何顯示以及遷移中需要的一組導(dǎo)入。

添加 deconstruct() 方法

你可以通過給類一個(gè) ?deconstruct()? 方法來讓Django序列化你的自定義類實(shí)例。它不帶任何參數(shù),應(yīng)該返回一個(gè)三個(gè)項(xiàng)目組成的元組? (path, args, kwargs)?:

  • ?path ?應(yīng)該是該類的 Python 路徑,并且類名作為最后一部分包括在內(nèi)(例如,?myapp.custom_things.MyClass?)。如果你的類在模塊的頂層不可用,那么它就不能被序列化。
  • ?args ?應(yīng)該是一個(gè)位置參數(shù)的列表,用來傳遞給你的類的 ?__init__? 方法。這個(gè)列表中的所有內(nèi)容本身應(yīng)該是可序列化的。
  • ?kwargs ?應(yīng)該是一個(gè)關(guān)鍵字參數(shù)的字典,用來傳遞給你的類的 ?__init__? 方法。每個(gè)值本身應(yīng)該是可序列化的。

此返回值與自定義字段的 ?deconstruct()? 方法不同,后者返回四個(gè)項(xiàng)組成的元組。

Django 會(huì)用給定的參數(shù)將值作為你的類的實(shí)例化寫出來,類似于它寫出對(duì) Django 字段的引用的方式。
為了防止每次運(yùn)行 ?makemigrations ?時(shí)都會(huì)創(chuàng)建一個(gè)新的遷移,你還應(yīng)該在裝飾類中添加一個(gè) ?__eq__()? 方法。這個(gè)函數(shù)將被 Django 的遷移框架調(diào)用,以檢測狀態(tài)之間的變化。
只要類構(gòu)造函數(shù)的所有參數(shù)本身都是可序列化的,就可以使用 ?django.utils.deconstruct? 的 ?@deconstructible? 類裝飾器添加 ?deconstruct()? 方法:

from django.utils.deconstruct import deconstructible

@deconstructible
class MyCustomClass:

    def __init__(self, foo=1):
        self.foo = foo
        ...

    def __eq__(self, other):
        return self.foo == other.foo

裝飾器添加邏輯以捕獲并保留進(jìn)入構(gòu)造函數(shù)的參數(shù),然后在調(diào)用 ?deconstruct()? 時(shí)準(zhǔn)確返回這些參數(shù)。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)