New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nested exclude support #640
Comments
personally I think it should be nested by default, we would just need to add a "break change" notice to the release. Anyone unhappy with that? |
Will it affect not only nested models, but also keys with plain dict values then? |
I see in this case For example model has two nested models and this models has the same keys and need to exclude key only from one of that. Need something like |
Imagine we have the following code: from pydantic import BaseModel
class Author(BaseModel):
name: str
surname: str
country: str
class Book(BaseModel):
name: str
author: Author
release_year: int
john_smith = Author(name='John', surname='Smith', country='England')
foo_bar_story = Book(name='The Foo Bar Story', author=john_smith, release_year=2019)
print(foo_bar_story.dict(exclude={'name'})) Does it mean, that both {'author': {'surname': 'Smith', 'country': 'England'}, 'release_year': 2019} It is not obvious, to be honest. At this point, it feels like we might need something like foo_bar_story.dict(projection={"name": 0, "author": {"name": 0}, "author.country": 0}) |
Okay, having thought about this, I think nested exclude and include should work as follows: members of the set for exclude can either be a string in which case they work as they currently do, or a tuple in which case they indicate the nested member to exclude. Same/opposite for include. So in the above example to exclude the author name you'd use foo_bar_story.dict(exclude={('author', 'name'}) If you had a list you could exclude via element id, eg. class Author(BaseModel):
name: str
surname: str
class Book(BaseModel):
name: str
authors: List[Author]
a1 = Author(name='c', surname='d')
a2 = Author(name='e', surname='f')
b = Book(name='testing', authors=[a1, a2])
# excluded a2:
b.dict(exclude={('authors', 1)}) This will make the logic fairly complicated and somewhat slower, but it's backwards compatible and powerful. |
I like this idea, but in this case personally I’d preferred using a foo_bar_story.dict(exclude={'author': {'name', 'id'}})
b.dict(exclude={'authors': {1, 2}}) What do you think? Upd. And for excluding entire key, for example we can use something like this: b.dict(exclude={'authors': ...}) |
dicts are mutable so can't be used in a set, let's go with
|
But why use them in a set? I suggested use either a set or a dict. I still don’t get benefits of using set of tuples. How will it look with multiple fields to exclude from nested model or depth > 1? |
Sorry, I though you had Maybe dict would be easier. Please explain what it would like when excluding the following things (all these things in the same exclude):
? (for reference with the tuple solution this would be |
if we wanted the tuple approach to be more succinct (but harder to develop) we could make the above example: exclude={
'name',
('address', ('post_code', 'country')),
'card_details',
('hobbies', -1),
} |
Above example should look like: exclude={
'name': ...,
'address': {'post_code', 'country'},
'card_details': ...,
'hobbies': {-1},
} I’m not sure about ellipses, maybe we should use something else to define entire field to exclude. Tuple solution seems to be more friendly for mixing single exclude in nested model and original exclude:
But when it comes to excluding multiple fields from sub model, using a dict seems easier for me |
I think tuples are more correct, but dict is more readable. Let's go with the dict approach. |
Another benefit from using dict: we can define whether to use old or new logic right away just with type checking the argument If use tuple solution, we will need to check each element at any time |
I've almost implemented this so far. Need to deal with typing issues and write the tests In current state his example is absolutely valid and working: exclude={
'name': ...,
'address': {
'post_code': ...,
'country': {'code'}
},
'card_details': ...,
'hobbies': {
-1: {'details'}
},
} |
Also, I need a little help with type for exclude arg. DictIntStrExclude = Dict[IntStr, Union[SetIntStr, 'DictIntStrExclude', ellipsis]]
exclude: Union['SetStr', 'DictIntStrExclude'] How is the proper type should look like? |
Will have to be |
Feature Request
As @JrooTJunior pointed out, now
dict
,json
andcopy
methods don't support exclude for nested models.Using keys from original
exclude
arg for nested models could be confusing in some cases and also potentially will break backwards compatibility.So I see a solution in adding new arg called
nested_exclude
ordeep_exclude
, keys in which will be excluded from all nested models and even dicts:The text was updated successfully, but these errors were encountered: