如何将JSON转换为Python对象?含复杂结构转换及后续DB数据校验需求
复杂JSON转Python对象及数据校验方案
你提供的JSON为Avro格式的结构化数据定义,以下是两种适配不同场景的实现方案:
方案1:无依赖基础转换
适合仅需要读取JSON属性、不需要额外校验的场景,直接用Python内置模块即可实现:
- 第一步:先将JSON解析为Python字典
import json # 从文件读取JSON,也可以直接用json.loads()解析JSON字符串 with open("schema.json", "r", encoding="utf-8") as f: schema_dict = json.load(f) # 直接通过字典方式访问属性,例如 schema_dict["fields"][0]["name"]
- 第二步(可选):转成支持
.访问的简易对象
如果不想用字典的方括号取值,可以通过递归转换为属性访问对象:
from types import SimpleNamespace def dict_to_object(d: dict): if isinstance(d, dict): return SimpleNamespace(**{k: dict_to_object(v) for k, v in d.items()}) elif isinstance(d, list): return [dict_to_object(item) for item in d] else: return d schema_obj = dict_to_object(schema_dict) # 之后可以直接用 . 访问属性,例如 schema_obj.namespace、schema_obj.fields[0].type
方案2:结构化类转换(适配后续DB数据校验)
如果需要做数据校验、字段类型自动转换,推荐用Pydantic实现结构化对象转换,自动校验字段类型、处理自定义逻辑(比如你示例中的日期、时间戳逻辑类型转换):
- 首先根据JSON中定义的字段规则,编写对应的Pydantic模型:
from typing import Optional from pydantic import BaseModel, field_validator from datetime import date, datetime class BloodDonor(BaseModel): id: int donor_number: str birth_date: date height: Optional[int] = None applicant_ts: Optional[datetime] = None arm_preference_ind: Optional[str] = None abo_ind: Optional[str] = None vein_grading_ind: Optional[str] = None # 自动转换int类型的日期(Avro默认date为1970年1月1日起的天数) @field_validator("birth_date", mode="before") def int_to_date(cls, value): if isinstance(value, int): return date.fromordinal(date(1970, 1, 1).toordinal() + value) return value # 自动转换毫秒级时间戳为Python datetime对象 @field_validator("applicant_ts", mode="before") def long_to_datetime(cls, value): if isinstance(value, int): return datetime.fromtimestamp(value / 1000) return value
- 用法示例:
不管是从JSON读取的业务数据还是从数据库查询出来的数据,都可以直接传入模型初始化,自动完成校验和类型转换:
# 示例业务数据 raw_data = { "id": 1001, "donor_number": "DN202405001", "birth_date": 19723, "height": 178, "applicant_ts": 1717228800000, "arm_preference_ind": "RIGHT", "abo_ind": "O+", "vein_grading_ind": "GRADE_1" } # 初始化自动校验,字段不匹配会直接抛出明确的错误信息 donor_obj = BloodDonor(**raw_data) # 校验完成后可以直接用属性访问,和DB查询结果直接对比即可,无需手动转格式 print(donor_obj.birth_date) # 输出为date类型的2023-12-25
内容的提问来源于stack exchange,提问作者Suresh S
相关产品推荐
相关产品推荐

