Pydantic will exclude the class variables which begin with an underscore. so if it fits your use case, you can rename your attribues.
class User(UserBase):
_user_id=str
some_other_field=str
....
Answer from N.Moudgil on Stack OverflowPydantic will exclude the class variables which begin with an underscore. so if it fits your use case, you can rename your attribues.
class User(UserBase):
_user_id=str
some_other_field=str
....
To exclude a field you can also use exclude in Field:
from pydantic import BaseModel, Field
class Mdl(BaseModel):
val: str = Field(
exclude=True,
title="val"
)
however, the advantage of adding excluded parameters in the Config class seems to be that you can get the list of excluded parameters with
print(Mdl.Config.exclude)
Pydantic v2 exclude parameter in Field and Annotated
Dynamically include/exclude fields from dumps
Struggling with Pydantic 'excludes'
`include` and `exclude` are not passed to field serializer contexts
I am playing around with Pydantic v2.5 and trying to see how the exclude works when set as a Field option. Let's imagine that I have a User BaseModel class and a Permissions BaseModel class. Both are used in the Config class.
We do not want to print the all User info, hence why I added the exclude in the Permissions class when the user is defined.
from typing import Annotated, Optional
from pydantic import BaseModel, Field
class User(BaseModel):
name: str
surname: str
card_id: str
class Permissions(BaseModel):
user: Annotated[User, Field(exclude=True)]
config_rule: str
class Config:
def __init__(self):
self.user = User(**dict(name="Name", surname="Surname", card_id="12343545"))
self.config_data = Permissions(user=self.user, config_rule="admin")
c = Config()
print(c.config_data.model_dump_json(indent=2))
In this case, the exclude set in the Permissions class seems to be working fine, in fact the print output is:
{
"config_rule": "admin"
}
However, if I change the Permissions class with:
class Permissions(BaseModel):
user: Optional[Annotated[User, Field(exclude=True)]]
config_rule: strThe output is:
{
"user": {
"name": "Name",
"surname": "Surname",
"card_id": "12343545"
},
"config_rule": "admin"
}And I am not sure I understand why. Any thoughts? Thanks.
I'm building an API that deals with a bunch of related data structures. And I'm currently struggling with some of the intricacies of Pydantic. Here's my problem. I hope someone out there is able to help me out here! :)
Consider a Pydantic schema like this:
class Node(BaseModel):
name: str
uuid: UUID
parent_node_uuid: UUID | None
With that it is possible to represent a hierarchical, tree-like data set. Individual node objects are related to each other through the parent_node_uuid property. Each parent node can have multiple children. But each child can only ever have a single parent. (in other words there is a self-referential one-to-many relationship)
Now, when outputting this data set through the api endpoint, I could simply use the above schema as my response_model. But instead I want to make the data more verbose and instead nest the model, so that the output of one node includes all the information about its parent and child nodes. The naive approach looks like this:
class Node(BaseModel):
name: str
uuid: UUID
parent_node: "Node" | None = None
child_nodes: List["Node"] = []Unfortunately, this does not work as intended. When I try to pass sqlalchemy objects (which do have the required relationships set up) to this Pydantic schema, I'm running into an infinite recursion and python crashes. The reason is that the parent_node includes the main node object inits child_nodes property. Similarly, each child_node of our main node will have the main node set as their parent_node. - it's easy to see how Pydantic gets stuck in an infinite loop here.
There is a solution to one part of this problem:
class Node(BaseModel):
name: str
uuid: UUID
parent_node: "Node" | None = Field(None, exclude={"child_nodes"})
child_nodes: List["Node"] = []Using the exclude option, we're able to remove the child_nodes from the parent. - That's one half of the issue resolved. The above model now works in cases where our main node doesn't have any children, but it has a parent. (more on this in the docs here)
Unfortunately though, this solution does not work with lists. I've tried the following without success:
class Node(BaseModel):
name: str
uuid: UUID
parent_node: "Node" | None = Field(None, exclude={"child_nodes"})
child_nodes: List["Node"] = Field([], exclude={"parent_node"})*Does anyone know how I can get the exclude parameter to work when dealing with a List of models? *
A possible solution that works for pydantic 2.* is to use the @model_serializer decorator. The decorator allows to define a custom serialization logic for a model.
# or `from typing import Annotated` for Python 3.9+
from typing_extensions import Annotated
from typing import Optional
from pydantic import BaseModel
from pydantic.functional_serializers import model_serializer
class OmitIfNone:
pass
class NoSerializeNoneModel(BaseModel):
@model_serializer
def _serialize(self):
omit_if_none_fields = {
k
for k, v in self.model_fields.items()
if any(isinstance(m, OmitIfNone) for m in v.metadata)
}
return {k: v for k, v in self if k not in omit_if_none_fields or v is not None}
class UserResponseModel(NoSerializeNoneModel):
id: int
msg: Annotated[Optional[str], OmitIfNone()] = None
You can see that the msg field is not serialized when None:
a = UserResponseModel(id=1)
print(a.json())
# {"id":1}
b = UserResponseModel(id=1, msg="Hello")
print(b.json())
# {"id":1,"msg":"Hello"}
Disclaimer: this answer was inspired by this comment on a related Github issue.
you can't do such thing with pydantic and even with more powerfull lib like attrs. The why may be because it is not a good way of returning json object, it is realy confusing for you, the api client and your test suite.
you may get some inspiration from elegant-way-to-remove-fields-from-nested-dictionaries.
you would be able to achieve something (not recommanded at all) by parsing your object jsoned and remove fiels folowing a logic.
exemple of key/value manipulation in nested dict:
import re
def dict_key_convertor(dictionary):
"""
Convert a dictionary from CamelCase to snake_case
:param dictionary: the dictionary given
:return: return a dict
"""
if not isinstance(dictionary, (dict, list)):
return dictionary
if isinstance(dictionary, list):
return [dict_key_convertor(elem) for elem in dictionary]
return {to_snake(key): dict_key_convertor(data) for key, data in dictionary.items()}
def to_snake(word) -> str:
"""
Convert all word from camel to snake case
:param word: the word given to be change from camelCase to snake_case
:return: return word variable in snake_case
"""
return re.sub(r'([A-Z]{2,}(?=[a-z]))', '\\1_', re.sub(r'([a-z])([A-Z]+)', '\\1_\\2', word)).lower()
with a bit of work you may achive something with this:
from typing import List
def dict_key_cleaner(dictionary):
if not isinstance(dictionary, (dict, list)):
return dictionary
if isinstance(dictionary, list):
return [dict_key_cleaner(elem) for elem in dictionary]
# change this return to work with dict
return {poper(key, dictionary): dict_key_cleaner(data) for key, data in dictionary.items()}
def poper(key, dictionary):
special_keys: List[str] = ["field_name","field_name1","field_name2"]
# do some stuff here
for spe_key in special_keys:
if key == spe_key and key.key_value is None:
dictionary.pop(key)
# add return of modified dict