Python/Pydantic -使用json对象的列表

c0vxltue  于 2024-01-09  发布在  Python
关注(0)|答案(4)|浏览(228)

我有一个使用pydantic接收json数据集的工作模型。模型数据集如下所示:

  1. data = {'thing_number': 123,
  2. 'thing_description': 'duck',
  3. 'thing_amount': 4.56}

字符串
我想做的是将json文件列表作为数据集,并能够对其进行验证。最终,该列表将转换为pandas中的记录,以供进一步处理。我的目标是验证一个任意长的json条目列表,如下所示:

  1. bigger_data = [{'thing_number': 123,
  2. 'thing_description': 'duck',
  3. 'thing_amount': 4.56},
  4. {'thing_number': 456,
  5. 'thing_description': 'cow',
  6. 'thing_amount': 7.89}]


我现在的基本设置如下。注意,添加class ItemList是尝试让任意长度工作的一部分。

  1. from typing import List
  2. from pydantic import BaseModel
  3. from pydantic.schema import schema
  4. import json
  5. class Item(BaseModel):
  6. thing_number: int
  7. thing_description: str
  8. thing_amount: float
  9. class ItemList(BaseModel):
  10. each_item: List[Item]


然后,基本代码将在一个数组对象中生成我认为我要查找的内容,该数组对象将接受Item对象。

  1. item_schema = schema([ItemList])
  2. print(json.dumps(item_schema, indent=2))
  3. {
  4. "definitions": {
  5. "Item": {
  6. "title": "Item",
  7. "type": "object",
  8. "properties": {
  9. "thing_number": {
  10. "title": "Thing_Number",
  11. "type": "integer"
  12. },
  13. "thing_description": {
  14. "title": "Thing_Description",
  15. "type": "string"
  16. },
  17. "thing_amount": {
  18. "title": "Thing_Amount",
  19. "type": "number"
  20. }
  21. },
  22. "required": [
  23. "thing_number",
  24. "thing_description",
  25. "thing_amount"
  26. ]
  27. },
  28. "ItemList": {
  29. "title": "ItemList",
  30. "type": "object",
  31. "properties": {
  32. "each_item": {
  33. "title": "Each_Item",
  34. "type": "array",
  35. "items": {
  36. "$ref": "#/definitions/Item"
  37. }
  38. }
  39. },
  40. "required": [
  41. "each_item"
  42. ]
  43. }
  44. }
  45. }


安装程序在传递的单个json项上工作:

  1. item = Item(**data)
  2. print(item)
  3. Item thing_number=123 thing_description='duck' thing_amount=4.56


但是,当我尝试将单个项传递到ItemList模型时,它返回一个错误:

  1. item_list = ItemList(**data)
  2. ---------------------------------------------------------------------------
  3. ValidationError Traceback (most recent call last)
  4. <ipython-input-94-48efd56e7b6c> in <module>
  5. ----> 1 item_list = ItemList(**data)
  6. /opt/conda/lib/python3.7/site-packages/pydantic/main.cpython-37m-x86_64-linux-gnu.so in pydantic.main.BaseModel.__init__()
  7. /opt/conda/lib/python3.7/site-packages/pydantic/main.cpython-37m-x86_64-linux-gnu.so in pydantic.main.validate_model()
  8. ValidationError: 1 validation error for ItemList
  9. each_item
  10. field required (type=value_error.missing)


我也试着将bigger_data传入数组,认为它需要以列表的形式开始。这也会返回一个错误- -尽管如此,我至少对字典错误有了更好的理解,但我不知道如何解决。

  1. item_list2 = ItemList(**data_big)
  2. ---------------------------------------------------------------------------
  3. TypeError Traceback (most recent call last)
  4. <ipython-input-100-8fe9a5414bd6> in <module>
  5. ----> 1 item_list2 = ItemList(**data_big)
  6. TypeError: MetaModel object argument after ** must be a mapping, not list


谢谢.
"我尝试过的其他事情“
我试着将数据传递到特定的键中,但运气稍好一些(也许?)

  1. item_list2 = ItemList(each_item=data_big)
  2. ---------------------------------------------------------------------------
  3. ValidationError Traceback (most recent call last)
  4. <ipython-input-111-07e5c12bf8b4> in <module>
  5. ----> 1 item_list2 = ItemList(each_item=data_big)
  6. /opt/conda/lib/python3.7/site-packages/pydantic/main.cpython-37m-x86_64-linux-gnu.so in pydantic.main.BaseModel.__init__()
  7. /opt/conda/lib/python3.7/site-packages/pydantic/main.cpython-37m-x86_64-linux-gnu.so in pydantic.main.validate_model()
  8. ValidationError: 6 validation errors for ItemList
  9. each_item -> 0 -> thing_number
  10. field required (type=value_error.missing)
  11. each_item -> 0 -> thing_description
  12. field required (type=value_error.missing)
  13. each_item -> 0 -> thing_amount
  14. field required (type=value_error.missing)
  15. each_item -> 1 -> thing_number
  16. field required (type=value_error.missing)
  17. each_item -> 1 -> thing_description
  18. field required (type=value_error.missing)
  19. each_item -> 1 -> thing_amount
  20. field required (type=value_error.missing)

dbf7pr2w

dbf7pr2w1#

为了避免在ItemList中包含"each_item",可以使用__root__ Pydantic关键字:

  1. from typing import List
  2. from pydantic import BaseModel
  3. class Item(BaseModel):
  4. thing_number: int
  5. thing_description: str
  6. thing_amount: float
  7. class ItemList(BaseModel):
  8. __root__: List[Item] # ⯇-- __root__

字符串
构建item_list

  1. just_data = [
  2. {"thing_number": 123, "thing_description": "duck", "thing_amount": 4.56},
  3. {"thing_number": 456, "thing_description": "cow", "thing_amount": 7.89},
  4. ]
  5. item_list = ItemList(__root__=just_data)
  6. a_json_duck = {"thing_number": 123, "thing_description": "duck", "thing_amount": 4.56}
  7. item_list.__root__.append(a_json_duck)


支持Pydantic的Web框架通常将ItemList作为JSON数组进行jsonify,而不使用中间的__root__关键字。

展开查看全部
ppcbkaq5

ppcbkaq52#

下面的代码也可以工作,并且不需要根类型。
List[dict]转换为List[Item]

  1. items = parse_obj_as(List[Item], bigger_data)

字符串
从JSON str转换为List[Item]

  1. items = parse_raw_as(List[Item], bigger_data_json)


List[Item]转换为JSON str

  1. from pydantic.json import pydantic_encoder
  2. bigger_data_json = json.dumps(items, default=pydantic_encoder)


或者使用自定义编码器:

  1. from pydantic.json import pydantic_encoder
  2. def custom_encoder(**kwargs):
  3. def base_encoder(obj):
  4. if isinstance(obj, BaseModel):
  5. return obj.dict(**kwargs)
  6. else:
  7. return pydantic_encoder(obj)
  8. return base_encoder
  9. bigger_data_json = json.dumps(items, default=custom_encoder(by_alias=True))

展开查看全部
x7rlezfr

x7rlezfr3#

  1. from typing import List
  2. from pydantic import BaseModel
  3. import json
  4. class Item(BaseModel):
  5. thing_number: int
  6. thing_description: str
  7. thing_amount: float
  8. class ItemList(BaseModel):
  9. each_item: List[Item]

字符串
基于您的代码,将each_item作为项目列表

  1. a_duck = Item(thing_number=123, thing_description="duck", thing_amount=4.56)
  2. print(a_duck.json())
  3. a_list = ItemList(each_item=[a_duck])
  4. print(a_list.json())


生成以下输出:

  1. {"thing_number": 123, "thing_description": "duck", "thing_amount": 4.56}
  2. {"each_item": [{"thing_number": 123, "thing_description": "duck", "thing_amount": 4.56}]}


使用这些作为“entry json”:

  1. a_json_duck = {"thing_number": 123, "thing_description": "duck", "thing_amount": 4.56}
  2. a_json_list = {
  3. "each_item": [
  4. {"thing_number": 123, "thing_description": "duck", "thing_amount": 4.56}
  5. ]
  6. }
  7. print(Item(**a_json_duck))
  8. print(ItemList(**a_json_list))


工作很好,并生成:

  1. Item thing_number=123 thing_description='duck' thing_amount=4.56
  2. ItemList each_item=[<Item thing_number=123 thing_description='duck' thing_amount=4.56>]


我们只剩下唯一的数据:

  1. just_datas = [
  2. {"thing_number": 123, "thing_description": "duck", "thing_amount": 4.56},
  3. {"thing_number": 456, "thing_description": "cow", "thing_amount": 7.89},
  4. ]
  5. item_list = ItemList(each_item=just_datas)
  6. print(item_list)
  7. print(type(item_list.each_item[1]))
  8. print(item_list.each_item[1])


这些工作如预期:

  1. ItemList each_item=[<Item thing_number=123 thing_description='duck'thing_amount=4.56>,<Item thin
  2. <class '__main__.Item'>
  3. Item thing_number=456 thing_description='cow' thing_amount=7.89


因此,如果我错过了一些东西,pydantic librairy工程作为预期。
我的pydantic版本:0.30 python 3.7.4
阅读类似文件:

  1. json_data_file = """[
  2. {"thing_number": 123, "thing_description": "duck", "thing_amount": 4.56},
  3. {"thing_number": 456, "thing_description": "cow", "thing_amount": 7.89}]"""
  4. from io import StringIO
  5. item_list2 = ItemList(each_item=json.load(StringIO(json_data_file)))


工作也很好。

展开查看全部
qybjjes1

qybjjes14#

对我来说,诀窍是fastapi.encoders.jsonable_encoder(看看https://fastapi.tiangolo.com/tutorial/encoder/
因此,在您的情况下,我已经将“单个”项目附加到列表result中,即result.append(Item(thing_number=123, thing_description="duck", thing_amount=4.56))
最后是fastapi.JSONResponse(content=fastapi.encoders.jsonable_encoder(result))

相关问题