Hello,
I was trying to run the Custom Field example but I get an error related to the keys being duplicate.
This is the example:
from marshmallow import fields, Schema, pprint
class TitleCased(fields.Field):
"""Field that serializes to a title case string and deserializes
to a lower case string.
"""
def _serialize(self, value, attr, obj, **kwargs):
if value is None:
return ""
return value.title()
def _deserialize(self, value, attr, data, **kwargs):
return value.lower()
class UserSchema(Schema):
name = fields.String()
email = fields.String()
created_at = fields.DateTime()
titlename = TitleCased(attribute="name")
This is the code snipet I use to run the example since the example seems to miss to tell how to actually test the example:
user_schema = UserSchema()
user = user_schema.load({"name": "John Doe", "email": "[email protected]", "created_at": datetime.utcnow().isoformat()})
pprint(user)
This is the result:
(venv) PS D:\Documents\Projects\research\marsh> python.exe .\poc.py Traceback (most recent call last):
File ".\poc.py", line 27, in <module>
user_schema = UserSchema()
File "D:\Documents\Projects\research\marsh\venv\lib\site-packages\marshmallow\schema.py", line 397, in __init__
self._init_fields()
File "D:\Documents\Projects\research\marsh\venv\lib\site-packages\marshmallow\schema.py", line 1008, in _init_fields
raise ValueError(
ValueError: The attribute argument for one or more fields collides with another field's name or attribute argument. Check the following field names and attribute arguments: ['name']
But if I change the schema definition to this:
class UserSchema(Schema):
# name = fields.String()
email = fields.String()
created_at = fields.DateTime()
name = TitleCased(attribute="name")
Then I get the following output:
{'created_at': datetime.datetime(2020, 3, 13, 20, 46, 42, 817528),
'email': '[email protected]',
'name': 'john doe'}
In conclusion I'm not sure if it's me doing something wrong or the documentation is not complete for this particular feature.
I'll gladly accept any help regarding this.
Cheers.
I was able to reproduce that behavior in the latest release. That example would need to set dump_only=True to avoid the collision and not try to read a computed value.
It would be even better if the example avoided reusing a field name to keep things as simple as possible. Maybe that example was chosen to keep the examples consistent with the method/function examples after it. That is not great use case for using a custom field though. Ideally it should be a simple transformation with validation.
from marshmallow import fields, ValidationError
class PinCode(fields.Field):
"""Field that serializes to a string of numbers and deserializes
to a list of numbers.
"""
def _serialize(self, value, attr, obj, **kwargs):
if value is None:
return ""
return ''.join(str(d) for d in value)
def _deserialize(self, value, attr, data, **kwargs):
try:
return [int(c) for c in value]
except ValueError:
raise ValidationError('Pin codes must contain only digits')
class UserSchema(Schema):
name = fields.String()
email = fields.String()
created_at = fields.DateTime()
pin_code = PinCode()
Thanks for taking the time to check this and clarifying the issue.
I was trying to do something like your example in my actual implementation, that's why I was reading the docs in the first place and got to that misleading example.
I've achieved something similar to your example while experimenting in the weekend which, at least for me, it better demonstrates the potential of custom fields.
I like the above example better than what's currently there. @deckar01 Would you like to update the docs?
Nice example @deckar01, updated docs in #1585 馃憤
Most helpful comment
I was able to reproduce that behavior in the latest release. That example would need to set
dump_only=Trueto avoid the collision and not try to read a computed value.It would be even better if the example avoided reusing a field name to keep things as simple as possible. Maybe that example was chosen to keep the examples consistent with the method/function examples after it. That is not great use case for using a custom field though. Ideally it should be a simple transformation with validation.