简体   繁体   English

如何在验证器 function 中获取 model pydantic 的 json

[英]How to get json of model pydantic in validator function

Imagine I have Model of pydantic like this:想象一下,我有像这样的 pydantic 的 Model:

 class Input(BaseModel): field1: ObjectIdField =... field2: str =... field3: int =... field4: str =... @validator('field4') def validate_field4(cls, v, values, **kwargs): # print(values) => {'field1': ObjectId('63185d5c721c6ef40eb2462a'), 'field2': 'deleted', 'field3': 1} # I want to check this # if json.dumps(values) == v: # OK # else: # raise Exception return v class Config: json_encoders = { ObjectId: lambda v: str(v), }

As you see, I want to get json of model except one field(field4).如您所见,我想获得 model 的 json 除了一个字段(字段4)。 Is there a good solution for handle this inside validator of model???有没有很好的解决方案来处理 model 的内部验证器?

What the comments failed to address is that Pydantics .json is an instance method (just like the .dict method) and thus completely useless inside a validator, which is always a class method called before an instance is even initialized.评论未能解决的是 Pydantics .json是一个实例方法(就像.dict方法一样),因此在验证器中完全没用,验证器始终是在实例初始化之前调用的class方法。

(Note: You did not provide code or explanation about how your ObjectIdField class works, so I had to make a guess and implement a very simple class to try and simulate the behavior you showed.) (注意:您没有提供有关您的ObjectIdField class 如何工作的代码或解释,因此我不得不猜测并实现一个非常简单的 class 来尝试模拟您显示的行为。)

Here is a way to accomplish your validation:这是完成验证的一种方法:

import json
from typing import Any

from pydantic import BaseModel, validator


class ObjectIdField:
    def __init__(self, value: str) -> None:
        self.value = value

    def __repr__(self) -> str:
        return f"ObjectId('{self.value}')"

    def __str__(self) -> str:
        return self.value


def encode_obj_id(obj_id: ObjectIdField) -> str:
    return str(obj_id)


def json_encode(obj: Any) -> str:
    return json.dumps(obj, default=encode_obj_id)


class Input(BaseModel):
    field1: ObjectIdField = ...
    field2: str = ...
    field3: int = ...
    field4: str = ...

    @validator('field4')
    def validate_field4(cls, v: str, values: dict[str, Any]) -> str:
        serialized = json_encode(values)
        assert v == serialized
        return v

    class Config:
        arbitrary_types_allowed = True  # to allow `ObjectIdField`
        json_encoders = {
            ObjectIdField: encode_obj_id,
        }


if __name__ == '__main__':
    data = dict(
        field1=ObjectIdField("abc"),
        field2="foo",
        field3=123,
    )
    data_json = json_encode(data)
    instance = Input(**data, field4=data_json)
    assert data_json == instance.json(exclude={"field4"})

    # instance = Input(**data, field4="invalid")  # this fails validation

The json.dumps function has a default parameter, which takes a function json.dumps function 有一个default参数,它采用 function

that gets called for objects that can't otherwise be serialized.对于无法以其他方式序列化的对象,会调用它。

We can use that to construct our own little helper function json_encode that serializes ObjectIdField types using the encode_obj_id function.我们可以使用它来构造我们自己的小助手 function json_encode ,它使用encode_obj_id function 序列化ObjectIdField类型。

Since field4 is not present in the values dictionary passed to the validator function for that field, we can simply call our json_encode function on that dictionary and compare it to the field4 value v .由于field4不存在于传递给该字段的验证器 function 的values字典中,我们可以简单地在该字典上调用我们的json_encode function 并将其与field4v进行比较。

NOTE : This only works, if field4 is defined last on the model because fields are validated in the order they are defined.注意:这仅适用于字段 4 在field4上最后定义的情况,因为字段按照定义的顺序进行验证。 If you had another field after field4 on your model, its value would be missing from the values dictionary by the time the validator was called.如果您在field4上的 field4之后有另一个字段,则在调用验证器时其值将从values字典中丢失。

Hope this helps.希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM