pydantic-core
pydantic-core copied to clipboard
The keyword argument `exclude` does not take effect when custom class uses `model_serializer`
Basic System Info
- python version: 3.11.2
- pydantic version: 2.0.2
- Platform: MacOS 13.2.1 M2 chip
Description
The exclude
keyword argument of model_dump
function does not work when there is a custom serialization function decorated with model_serializer(when_used='json')
. I would expect the custom serialization process will only be invoked when using model_dump_json
or model_dump(mode='json')
, but it seems like this will also affects the normal model_dump
behaviour.
Take the following code as example:
from pydantic import BaseModel, model_serializer
class Test(BaseModel):
a: int = 123
b: str = 'bob'
@model_serializer(when_used='json')
def ser_model(self):
out = {}
for k, v in self:
if isinstance(v, str):
out[k] = v.title()
else:
out[k] = v
return out
t = Test()
# This prints normally
print(t.model_dump()) # {'a': 123, 'b': 'bob'}
# This also works as expected
print(t.model_dump_json()) # {'a': 123, 'b': 'Bob'}
# But this doesn't
print(t.model_dump(exclude={'b'})) # {'a': 123, 'b': 'bob'}
The last case of using exclude
in model_dump
does not really exclude the specified column in the output. Everything would just work fine by removing the ser_model
function, therefore the problem must be within ser_model
itself.
I have also tried to pass the mode='wrap'
to model_serializer
and redefined the function signature as documented to the following:
from typing import Any
from pydantic import BaseModel, model_serializer
class Test(BaseModel):
a: int = 123
b: str = 'bob'
@model_serializer(mode='wrap', when_used='json')
def ser_model(self, serializer: Any, handler: pydantic.SerializerFunctionWrapHandler):
out = {}
for k, v in self:
if isinstance(v, str):
out[k] = v.title()
else:
out[k] = v
return serializer(out)
t = Test()
# Still doesn't work
print(t.model_dump(exclude={'b'})) # {'a': 123, 'b': 'bob'}
The above still doesn't work, and after testing all different cases, I suspect the model_serializer
not only overrides the serialization process to 'json' mode only, but also to other scenarios even if the argument when_used='json'
.
I tried removing when_used
in model_serializer
to make it apply to both json and dict dump cases, and it 'kind of' works, rather I received a UserWarning
saying that the Pydantic serializer expected type of Test
and not dict
(this occurs at the last line, the return
statement).
To this point, there are three things that confuse me:
- How to make
model_serializer
work correctly given the above scenario? - Why is there so little explanation to the meaning of each argument of
model_serialization
? Says the usage ofmode='wrap'
, why is the correct function signature of the decorated function being listed in theUsage Error
page, and not under the API reference page? For me, I would expect all use cases being listed under API reference page or tutorial page. - Related to the above, the function signature provided in the official document annotated the first additional argument (the
serializer
defined in the above code example, and thevalue
in the document) as type ofAny
, which does not give much information of what it really is. And when print the variable type in the console, I can see the actual type isSerializationCallable
, which until then I understand I can call it at the last return statement. Isn't it much better to explicitly point this as well in the document? Both the in the API reference and the Usage Error page.
Still thanks for the awesome work and the extraordinary Rust migration. Hope there could be someone helping on this issue.
Selected Assignee: @samuelcolvin
Thanks for reporting this. I think it's probably worth moving this issue to the pydantic repo even if the fix needs to be in pydantic-core, just for increased visibility.
Oh, I didn't notice that. Thanks for the suggestion. I will open a new issue there as well.
Think this issue also related to this one https://github.com/pydantic/pydantic/issues/6736
@samuelcolvin @BreezeWhite i think you can close this issue because this one pydantic/pydantic#6736 was closed
Hi @donBarbos . Thanks for the reminding. Closing this issue