簡體   English   中英

Pydantic:如何在子類驗證器中調用超類方法?

[英]Pydantic: How do I call a superclass method inside a subclass validator?

我正在嘗試使用超類方法驗證子類,但我做的事情根本上是錯誤的,無法弄清楚。

from pydantic import BaseModel, validator, root_validator

class Name(BaseModel):
  name: str

  def name_has_two_parts(self):
    return len(self.name.split())==2

class FirstLast(Name):
    @root_validator(pre=True)
    @classmethod
    def check_parts(cls, values):
        #assert len(values["name"].split())==2  # <-- this works fine
        assert super().name_has_two_parts(), f'Some message here'  # <-- this does NOT work
        return values

first_last = FirstLast(name="First Last")

有了這個我得到以下錯誤:

ValidationError: 1 validation error for FirstLast
__root__
  name_has_two_parts() missing 1 required positional argument: 'self' (type=type_error)

任何幫助將不勝感激。 謝謝!

您的主要問題如下:

從 class 方法調用實例方法

由於check_parts是一個(根)驗證器,它是一個class 方法 (第一個參數稱為cls的事實也暗示了這一點。)這是正確的,因為這就是 Pydantic 驗證器的工作方式。 它們在 model 實例完全初始化之前被調用。

但是,您的name_has_two_parts方法是Name class 的實例方法,inheritance 也是FirstLast class 的實例方法。(第一個參數再次暗示self 。)這本身就很好,因為我假設您想使用它與Name的實例一樣,就像這樣:

instance = Name(name="foo bar")
print(instance.name_has_two_parts())  # output: `True`

但是你不能從 class 調用它,即這不起作用:

Name.name_has_two_parts()  # TypeError: Name.name_has_two_parts() missing 1 required positional argument: 'self'

沒有self可以提供,因為該調用中不存在任何實例。

然而,這正是您在 class 方法中所做的:

...
    def check_parts(cls, values):
        assert super().name_has_two_parts()

class 方法中的super調用等效於super(FirstLast, cls).name_has_two_parts() ,這反過來導致name_has_two_parts方法像我上面所做的那樣在Name class 上被調用。

一種可能的解決方案是將檢查部件數量的邏輯分解到它自己的static方法中(因為它不依賴於任何 class 或實例屬性),然后在實例方法和驗證器中分別調用它:

from typing import Any

from pydantic import BaseModel, root_validator


class Name(BaseModel):
    name: str

    @staticmethod
    def has_two_parts(string: str) -> bool:
        return len(string.split()) == 2

    def name_has_two_parts(self) -> bool:
        return self.has_two_parts(self.name)


class FirstLast(Name):
    @root_validator(pre=True)
    def check_parts(cls, values: dict[str, Any]) -> dict[str, Any]:
        assert cls.has_two_parts(values["name"]), "Some message here"
        return values


if __name__ == '__main__':
    first_last = FirstLast(name="First Last")
    assert first_last.name_has_two_parts()
    # wrong = FirstLast(name="First Last Third")  # causes a `ValidationError`

作為旁注, @classmethod裝飾器不需要與@root_validator (或常規的@validator )一起使用。

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM