【问题标题】:Is there a way to validate some JSON fields while keeping it general for non-mapped fields?有没有办法验证一些 JSON 字段,同时保持非映射字段的通用性?
【发布时间】:2022-07-26 22:28:05
【问题描述】:

我正在使用模型中的旧版“元”字段。

这个字段过去没有被记录或验证,所以它在没有太多结构的情况下被到处使用。

现在我想添加一个新字段并对其进行验证,同时不破坏旧的用法。

想一想:

from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy import BaseModel

class Object(BaseModel):
   #...
   old_field = JSONB('old_field')

   def set_old_field(self, inp: str):
      self.old_field = inp

现在我想在 old_field 中添加一个 foo 字段,我有这样的结构:

{"foo": 
  {
    "settings":
      {"color":"blue",
       "position":"top"},
    "active":false
  }
}

我怎么能这样做(也许使用 pydantic),同时允许除 foo 之外的任何其他键在没有验证的情况下通过?

【问题讨论】:

  • 我尝试在 Pydantic 中使用 Union[FooField, JSON],但它不起作用(当你有 FooField 时没有验证。

标签: python sqlalchemy pydantic


【解决方案1】:

我在 pydantic docs 中找到了一个基于使用 get_validators 的解决方案:

基本上,我们必须重写验证器才能检查特定键并忽略其他键,如下所示:

from pydantic import BaseModel, ValidationError
import json

class SpecialField(BaseModel):
   foo: str
   bar: int

class FlexibleJson(str):

   validated_fields = {'special_field':SpecialField}

   @classmethod
   def __get_validators__(cls):
      yield cls.validate

   @classmethod
   def validate(cls, v):
      try:
         validated = json.loads(v)
         for field in validated_fields:
             # you can do try/catching here to sum up all the validation errors
             if field in validated:
                #replace dict with a validated field
                validated[field]=validated_fields[field](**validated[field])
      except ValidationError as e:
         raise
      except Exception as excp:
         raise ValidationError(error=[excp], model=cls.__name__)
      return cls(validated)


class ObjModel(BaseModel):
   metadata: FlexibleJson

#works:
obj1 = ObjModel(**{"metadata":'{"special_field":{"foo":"zazz","bar":7}, "baz":"whatever"}'})

#works - no special_field:
obj2 = ObjModel(**{"metadata":'{"baz":"whatever"}'})

#fails - wrong type
obj3 = ObjModel(**{"metadata":'{"special_field":{"foo":"zazz","bar":"zoooo"}, "baz":"whatever"}'})

#fails - missing
obj4 = ObjModel(**{"metadata":'"special_field":{"foo":"zazz"}, "baz":"whatever"}'})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多