Reputation: 14037
In pydantic is there a cleaner way to exclude multiple fields from the model, something like:
class User(UserBase):
class Config:
exclude = ['user_id', 'some_other_field']
I am aware that following works.
class User(UserBase):
class Config:
fields = {'user_id': {'exclude':True},
'some_other_field': {'exclude':True}
}
but I was looking for something cleaner like django rest framework, where you could just specify a list of exclude or include per.
Upvotes: 29
Views: 81357
Reputation: 15210
At the time I'm posting this answer, the stable release of Pydantic is version 2.7.x
The PrivateAttr class in Pydantic 2.x provides a solution. You can mark one or more fields in your model class as private by prefixing each field name with an underscore and assigning that field to PrivateAttr. Here is an example:
class ExampleModelClassAlpha(BaseModel):
name: str
power_animal: Optional[str] = None
_private: str = PrivateAttr(default=None)
Here is a simple Pytest that demonstrates how it works:
import logging
import pytest
from typing import Optional
from pydantic import BaseModel, PrivateAttr
logger = logging.getLogger(__name__)
class ExampleModelClassAlpha(BaseModel):
name: str
power_animal: Optional[str] = None
_private: str = PrivateAttr(default=None)
# -------------------------------------------------------------------------------------------------
# noinspection PyArgumentList
@pytest.mark.unit
class TestSummaOpenapiModel:
# ---------------------------------------------------------------------------------------------
def test_x(self):
emc_alpha: ExampleModelClassAlpha = ExampleModelClassAlpha(
name='John Smith',
_private='this is a private field that I want to exclude from the JSON'
)
the_json_string: str = emc_alpha.model_dump_json(indent=4, exclude_none=True)
logger.info("\n%s", the_json_string)
assert 'power_animal' not in the_json_string
assert 'this is a private field' not in the_json_string
The test should pass, and the output should look like this:
{
"name": "John Smith"
}
Upvotes: 1
Reputation: 440
I wrote something like this for my json :
from pydantic import BaseModel
class CustomBase(BaseModel):
def json(self, **kwargs):
include = getattr(self.Config, "include", set())
if len(include) == 0:
include = None
exclude = getattr(self.Config, "exclude", set())
if len(exclude) == 0:
exclude = None
return super().json(include=include, exclude=exclude, **kwargs)
class User(CustomBase):
name: str = ...
family: str = ...
class Config:
exclude = {"family"}
u = User(**{"name": "milad", "family": "vayani"})
print(u.json())
you can overriding dict and other method like.
Upvotes: 7
Reputation: 631
You can either do it in the field level or when serializing the model (see docs). Currently there is a stale issue for having include / exclude in the model_config.
from typing import Annotated
from pydantic import BaseModel, Field
class A(BaseModel):
foo: str = Field('bar', exclude=True)
bar: Annotated[int, Field(exclude=True)] = 'bar'
baz: str = 'bar'
a = A()
assert 'baz' not in a.model_dump(exclude={'baz'})
assert 'baz' in a.model_dump()
assert 'foo' not in a.model_dump()
Upvotes: 9
Reputation: 9
For pydantic2 you can use do something like:
class User(UserBase):
user_id: Annotated[int, Field(exclude=True)]
some_other_field: str
This can be much cleaner
Upvotes: -1
Reputation: 3283
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)
Upvotes: 11
Reputation: 2102
A possible solution is creating a new class based in the baseclass using create_model:
from pydantic import BaseModel, create_model
def exclude_id(baseclass, to_exclude: list):
# Here we just extract the fields and validators from the baseclass
fields = baseclass.__fields__
validators = {'__validators__': baseclass.__validators__}
new_fields = {key: (item.type_, ... if item.required else None)
for key, item in fields.items() if key not in to_exclude}
return create_model(f'{baseclass.__name__}Excluded', **new_fields, __validators__=validators)
class User(BaseModel):
ID: str
some_other: str
list_to_exclude = ['ID']
UserExcluded = exclude_id(User, list_to_exclude)
UserExcluded(some_other='hola')
Which will return:
> UserExcluded(some_other='hola')
Which is a copy of the baseclass but with no parameter 'ID'.
If you have the id in the validators you may want also to exclude those validators.
Upvotes: 2
Reputation: 869
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
....
Upvotes: 22