是否可以扩展使用DataModel-Code-Menerator生成的Pydantic模型?

发布于 2025-01-27 00:04:21 字数 1972 浏览 1 评论 0原文

我正在使用 datamodel-code-generator 生成 pydantic Models 来自JSON模式。

这是 json schema> json Schema 使用。

以及运行DataModel代码生成器后生成的模型。

# File: datamodel.py
from __future__ import annotations
from typing import List
from pydantic import BaseModel

class Record(BaseModel):
    id: int
    name: str

class Table(BaseModel):
    records: List[Record]

class Globals(BaseModel):
    table: Table

我一直在尝试扩展具有新属性的生成类。

# File: extensions.py
import json
from datamodel import Table, Globals

class ExtendedTable(Table):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('ExtendedTable Constructor')

        # Won't work because "ExtendedTable" object has no field "records_by_id"
        self.records_by_id = {record.id: record for record in self.records}

class ExtendedGlobals(Globals):
    def __init__(self, table: ExtendedTable):
        super().__init__(table=table)
        print('ExtendedGlobals Constructor')

if __name__ == '__main__':
    records = '''
    {
        "table": {
            "records": [{"id": 0, "name": "A"}, {"id": 1, "name": "B"}]
        }
    }
    '''

    content = json.loads(records)

    # Both won't call ExtendedTable.__init__()
    ExtendedGlobals(**content)
    ExtendedGlobals.parse_obj(content)

    ExtendedGlobals(table=ExtendedTable(**content['table']))

但是,我还没有找到使Globals类使用表的扩展定义的方法。 另外,仅在子类中添加新字段似乎不起作用。

有没有办法扩展这些类而不必修改Pydantic生成的模型?还是另一个从JSON模式生成Python代码的工具?

I am using the datamodel-code-generator to generate pydantic models from a JSON schema.

Here is the JSON schema used.

And the generated models after running the datamodel-code-generator.

# File: datamodel.py
from __future__ import annotations
from typing import List
from pydantic import BaseModel

class Record(BaseModel):
    id: int
    name: str

class Table(BaseModel):
    records: List[Record]

class Globals(BaseModel):
    table: Table

I've been trying to extend the generated classes with new attributes.

# File: extensions.py
import json
from datamodel import Table, Globals

class ExtendedTable(Table):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('ExtendedTable Constructor')

        # Won't work because "ExtendedTable" object has no field "records_by_id"
        self.records_by_id = {record.id: record for record in self.records}

class ExtendedGlobals(Globals):
    def __init__(self, table: ExtendedTable):
        super().__init__(table=table)
        print('ExtendedGlobals Constructor')

if __name__ == '__main__':
    records = '''
    {
        "table": {
            "records": [{"id": 0, "name": "A"}, {"id": 1, "name": "B"}]
        }
    }
    '''

    content = json.loads(records)

    # Both won't call ExtendedTable.__init__()
    ExtendedGlobals(**content)
    ExtendedGlobals.parse_obj(content)

    ExtendedGlobals(table=ExtendedTable(**content['table']))

However, I haven't found a way to make the Globals class use the extended definition of the table.
Also, simply adding new fields to the subclass does not seem to work.

Is there a way to extend these classes without having to modify the pydantic generated models? Or maybe another tool to generate Python code from JSON schema?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

绮筵 2025-02-03 00:04:22

我没有找到使Globals类使用表的扩展定义

的方法

如果您使用所需类型再次声明该字段,则可以更改子类中的字段类型。

另外,仅在子类中添加新字段似乎不起作用

它看起来您正在设置__ init __ init __()方法中的实例属性,但是将字段声明为类属性。

此示例显示了一种将计算出的字段Records_by_id添加到ExtendedTable并使用ExtendedTable in extendedGlobals

# File: extensions.py
import json
from typing import Any, Dict, List, Optional

from pydantic import Field, validator

from datamodel import Globals, Record, Table


class ExtendedTable(Table):
    # New fields are declared as class attributes not as instance attributes inside the __init__()
    # Calculated fields usually have a default value or default factory so that you don't have to provide a value
    # I prefer a default_factory for mutable values
    records_by_id: Dict[int, Record] = Field(default_factory=dict)

    # A validator can populate a calculated field
    # Use always=True to run the validator even if a value is not supplied and the default value is used
    @validator("records_by_id", always=True)
    def _calculate_records_by_id(
        cls, value: Dict[int, Record], values: Dict[str, Any]
    ) -> Dict[int, Record]:
        records: Optional[List[Record]] = values.get("records")
        if records is None:
            # The records field was not valid
            # Return value or raise a ValueError instead if you want
            return value
        return {record.id: record for record in records}


class ExtendedGlobals(Globals):
    # You can change the type of a field in a subclass if you declare the field again
    table: ExtendedTable


if __name__ == "__main__":
    records = """
    {
        "table": {
            "records": [{"id": 0, "name": "A"}, {"id": 1, "name": "B"}]
        }
    }
    """

    content = json.loads(records)
    extended_globals = ExtendedGlobals.parse_obj(content)
    print(repr(extended_globals))

输出:输出:输出:输出:

ExtendedGlobals(table=ExtendedTable(records=[Record(id=0, name='A'), Record(id=1, name='B')], records_by_id={0: Record(id=0, name='A'), 1: Record(id=1, name='B')}))

I haven't found a way to make the Globals class use the extended definition of the table

You can change the type of a field in a subclass if you declare the field again using the desired type.

Also, simply adding new fields to the subclass does not seem to work

It looks like you are setting instance attributes in the __init__() method, but fields are declared as class attributes.

This example shows a way to add a calculated field records_by_id to ExtendedTable and use ExtendedTable in ExtendedGlobals:

# File: extensions.py
import json
from typing import Any, Dict, List, Optional

from pydantic import Field, validator

from datamodel import Globals, Record, Table


class ExtendedTable(Table):
    # New fields are declared as class attributes not as instance attributes inside the __init__()
    # Calculated fields usually have a default value or default factory so that you don't have to provide a value
    # I prefer a default_factory for mutable values
    records_by_id: Dict[int, Record] = Field(default_factory=dict)

    # A validator can populate a calculated field
    # Use always=True to run the validator even if a value is not supplied and the default value is used
    @validator("records_by_id", always=True)
    def _calculate_records_by_id(
        cls, value: Dict[int, Record], values: Dict[str, Any]
    ) -> Dict[int, Record]:
        records: Optional[List[Record]] = values.get("records")
        if records is None:
            # The records field was not valid
            # Return value or raise a ValueError instead if you want
            return value
        return {record.id: record for record in records}


class ExtendedGlobals(Globals):
    # You can change the type of a field in a subclass if you declare the field again
    table: ExtendedTable


if __name__ == "__main__":
    records = """
    {
        "table": {
            "records": [{"id": 0, "name": "A"}, {"id": 1, "name": "B"}]
        }
    }
    """

    content = json.loads(records)
    extended_globals = ExtendedGlobals.parse_obj(content)
    print(repr(extended_globals))

Output:

ExtendedGlobals(table=ExtendedTable(records=[Record(id=0, name='A'), Record(id=1, name='B')], records_by_id={0: Record(id=0, name='A'), 1: Record(id=1, name='B')}))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文