繁体   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