如何根据其他字段设置Pydantic字段的值

huangapple go评论99阅读模式
英文:

How to set a Pydantic field value depending on other fields

问题

  1. from pydantic import BaseModel
  2. class Grafana(BaseModel):
  3. user: str
  4. password: str
  5. host: str
  6. port: str
  7. api_key: str | None = None
  8. @property
  9. def GRAFANA_URL(self):
  10. return f"http://{self.user}:{self.password}@{self.host}:{self.port}"
  11. API_DATASOURCES = "/api/datasources"
  12. API_KEYS = "/api/auth/keys"
英文:
  1. from pydantic import BaseModel
  2. class Grafana(BaseModel):
  3. user: str
  4. password: str
  5. host: str
  6. port: str
  7. api_key: str | None = None
  8. GRAFANA_URL = f"http://{user}:{password}@{host}:{port}"
  9. API_DATASOURCES = "/api/datasources"
  10. API_KEYS = "/api/auth/keys"

With Pydantic I get two unbound variables error messages for user, password, etc. in GRAFANA_URL.

Is there a way to solve this? In a regular class, I would just create GRAFANA_URL in the __init__ method. With Pydantic, I'm not sure how to proceed.

答案1

得分: 5

Option A: 使用@validator

请查看验证器文档以获取详细信息。

  1. from typing import Any
  2. from pydantic import BaseModel, validator
  3. class Model(BaseModel):
  4. foo: str
  5. bar: str
  6. foobar: str = ""
  7. @validator("foobar", always=True)
  8. def set_if_empty(cls, v: str, values: dict[str, Any]) -> str:
  9. if v == "":
  10. return values["foo"] + values["bar"]
  11. return v
  12. obj = Model(foo="a", bar="b")
  13. print(obj) # foo='a' bar='b' foobar='ab'

这样,foobar仍然是一个常规模型字段。

请注意,为了使此功能正常工作,foobar必须在foobar之后定义。否则,您将不得不使用根验证器

Option B: 将其作为@property

  1. from pydantic import BaseModel
  2. class Model(BaseModel):
  3. foo: str
  4. bar: str
  5. @property
  6. def foobar(self) -> str:
  7. return self.foo + self.bar
  8. obj = Model(foo="a", bar="b")
  9. print(obj) # foo='a' bar='b'
  10. print(obj.foobar) # ab

然后foobar将不再是模型字段,因此不会包含在模式中。这可能与您相关或不相关。

Option C: 将其作为@computed_field(仅适用于Pydantic v2!)

定义计算字段将在Pydantic 2中可用。

  1. from pydantic import BaseModel, computed_field
  2. class Model(BaseModel):
  3. foo: str
  4. bar: str
  5. @computed_field
  6. @property
  7. def foobar(self) -> str:
  8. return self.foo + self.bar
  9. obj = Model(foo="a", bar="b")
  10. print(obj) # foo='a' bar='b' foobar='ab'
英文:

Option A: Use a @validator

See the validators documentation for details.

  1. from typing import Any
  2. from pydantic import BaseModel, validator
  3. class Model(BaseModel):
  4. foo: str
  5. bar: str
  6. foobar: str = ""
  7. @validator("foobar", always=True)
  8. def set_if_empty(cls, v: str, values: dict[str, Any]) -> str:
  9. if v == "":
  10. return values["foo"] + values["bar"]
  11. return v
  12. obj = Model(foo="a", bar="b")
  13. print(obj) # foo='a' bar='b' foobar='ab'

That way foobar remains a regular model field.

Note that for this to work, foobar must be defined after foo and bar. Otherwise you will have to use a root validator.

Option B: Make it a @property

  1. from pydantic import BaseModel
  2. class Model(BaseModel):
  3. foo: str
  4. bar: str
  5. @property
  6. def foobar(self) -> str:
  7. return self.foo + self.bar
  8. obj = Model(foo="a", bar="b")
  9. print(obj) # foo='a' bar='b'
  10. print(obj.foobar) # ab

Then foobar will not be a model field anymore and therefore not part of the schema. That may or may not be relevant to you.

Option C: Make it a @computed_field (Pydantic v2 only!)

Defining computed fields will be available for Pydantic 2.

  1. from pydantic import BaseModel, computed_field
  2. class Model(BaseModel):
  3. foo: str
  4. bar: str
  5. @computed_field
  6. @property
  7. def foobar(self) -> str:
  8. return self.foo + self.bar
  9. obj = Model(foo="a", bar="b")
  10. print(obj) # foo='a' bar='b' foobar='ab'

huangapple
  • 本文由 发表于 2023年5月22日 04:35:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76301828.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定