Basemodel 属性改名/添加/删除

如果basemodel如何一个字段可以有也可以没有

Pydantic BaseModel 里,一个字段“可以有也可以没有”,通常这样写:

from pydantic import BaseModel
from typing import Optional

class User(BaseModel):
    name: str
    age: Optional[int] = None

这样 age 就是可选字段:

User(name="Tom")
# age=None

User(name="Tom", age=18)
# age=18

如果是 Python 3.10+,也可以写成:

class User(BaseModel):
    name: str
    age: int | None = None

关键点是:

age: int | None = None

表示:

  1. age 可以是 int
  2. 也可以是 None
  3. 不传这个字段也可以

注意不要只写:

age: Optional[int]

在一些 Pydantic 版本里,这表示值可以是 None,但字段本身仍然可能是必填的。最稳妥写法是加默认值:

age: Optional[int] = None

那如何同时=Field

可以同时用 Field,把默认值放在 Field 的第一个参数里:

from pydantic import BaseModel, Field

class User(BaseModel):
    name: str
    age: int | None = Field(default=None, description="用户年龄")

或者更简洁:

class User(BaseModel):
    name: str
    age: int | None = Field(None, description="用户年龄")

这样 age 就是:可以不传、可以传 None、也可以传 int

User(name="Tom")
User(name="Tom", age=None)
User(name="Tom", age=18)

如果你想“字段可以不传,但一旦传了就不能是 None”,则写成:

class User(BaseModel):
    name: str
    age: int = Field(default=None, description="用户年龄")

不过这个写法在类型语义上不太严谨,因为默认值是 None,类型却是 int。更推荐前面的:

age: int | None = Field(default=None, description="用户年龄")

User声明的对象如何添加属性

如果是 Pydantic BaseModel 的对象,比如:

from pydantic import BaseModel

class User(BaseModel):
    name: str

user = User(name="Tom")

默认情况下,能不能“临时添加新属性”取决于 Pydantic 版本和配置。

推荐方式:在模型里先声明字段

class User(BaseModel):
    name: str
    age: int | None = None

user = User(name="Tom")
user.age = 18

这是最推荐的方式。

允许动态添加额外属性

Pydantic v2:

from pydantic import BaseModel, ConfigDict

class User(BaseModel):
    model_config = ConfigDict(extra="allow")

    name: str

user = User(name="Tom")
user.age = 18

print(user.age)

Pydantic v1:

from pydantic import BaseModel

class User(BaseModel):
    name: str

    class Config:
        extra = "allow"

user = User(name="Tom")
user.age = 18

print(user.age)

不修改原对象,生成一个带新值的新对象

如果属性已经在模型里声明过,可以用:

Pydantic v2:

new_user = user.model_copy(update={"age": 18})

Pydantic v1:

new_user = user.copy(update={"age": 18})

总结一下:如果这个属性是业务字段,最好在 User 里声明;如果确实需要运行时动态加字段,就配置 extra="allow"

如何删除属性

Pydantic BaseModel 对象里删除属性,分几种情况。

1. 普通 Python 方式:delattr

如果模型允许额外字段,或者字段本身存在:

delattr(user, "age")

等价于:

del user.age

例如:

from pydantic import BaseModel, ConfigDict

class User(BaseModel):
    model_config = ConfigDict(extra="allow")
    name: str

user = User(name="Tom")
user.age = 18

del user.age

2. 更安全:先判断有没有

if hasattr(user, "age"):
    delattr(user, "age")

3. 如果是模型声明字段,不建议真的删除

例如:

class User(BaseModel):
    name: str
    age: int | None = None

虽然可以尝试:

del user.age

但删除后这个对象可能变得“不完整”,后面访问可能报错:

print(user.age)  # 可能 AttributeError

更推荐把它设为 None

user.age = None

4. 不修改原对象,生成一个“去掉字段”的 dict

很多时候你不是要真的删除属性,而是导出时不包含它:

Pydantic v2:

data = user.model_dump(exclude={"age"})

Pydantic v1:

data = user.dict(exclude={"age"})

5. 删除动态额外字段

Pydantic v2 里,如果是 extra="allow" 添加的额外字段,也可以这样:

if "age" in user.model_extra:
    del user.model_extra["age"]

不过一般直接用:

delattr(user, "age")

就够了。

basemodel如何挑选特定字段转换为json,这些字段可能存在嵌套结构

在 Pydantic 里,推荐用 include 来“挑选特定字段”,再转 JSON。嵌套结构也可以用字典形式指定。

Pydantic v2

json_str = user.model_dump_json(
    include={
        "name": True,
        "profile": {
            "email": True,
            "address": {
                "city": True
            }
        }
    }
)

例如:

from pydantic import BaseModel

class Address(BaseModel):
    city: str
    country: str

class Profile(BaseModel):
    email: str
    phone: str
    address: Address

class User(BaseModel):
    id: int
    name: str
    password: str
    profile: Profile

user = User(
    id=1,
    name="Tom",
    password="secret",
    profile={
        "email": "tom@example.com",
        "phone": "123456",
        "address": {
            "city": "Shanghai",
            "country": "China"
        }
    }
)

json_str = user.model_dump_json(
    include={
        "id": True,
        "name": True,
        "profile": {
            "email": True,
            "address": {
                "city": True
            }
        }
    }
)

print(json_str)

输出类似:

{"id":1,"name":"Tom","profile":{"email":"tom@example.com","address":{"city":"Shanghai"}}}

Pydantic v1

json_str = user.json(
    include={
        "id": True,
        "name": True,
        "profile": {
            "email": True,
            "address": {
                "city": True
            }
        }
    }
)

嵌套列表里的字段

如果字段是列表,例如:

class Order(BaseModel):
    id: int
    price: float
    secret: str

class User(BaseModel):
    name: str
    orders: list[Order]

只保留每个订单的 idprice

json_str = user.model_dump_json(
    include={
        "name": True,
        "orders": {
            "__all__": {
                "id": True,
                "price": True
            }
        }
    }
)

Pydantic v1 也是类似:

json_str = user.json(
    include={
        "name": True,
        "orders": {
            "__all__": {
                "id": True,
                "price": True
            }
        }
    }
)

如果只是想得到 dict

Pydantic v2:

data = user.model_dump(include={...})

Pydantic v1:

data = user.dict(include={...})

核心写法就是:

include = {
    "字段1": True,
    "嵌套字段": {
        "子字段": True
    },
    "列表字段": {
        "__all__": {
            "子字段": True
        }
    }
}
posted @ 2026-05-22 18:02  X1OO  阅读(23)  评论(0)    收藏  举报