A DateTime field to track updated_at timestamp on the model
A marshmallow-based custom de/serialization (and the corresponding marshmallow_enum) to correctly deserialize enums
problem
PATCH requests to update enum fields fail because the resources.py:patch() relies on directly setting the attributes of the sqlalchemy model instance to whatever values are provided by the request data dictionary (which are usually string/unicode representations of model field values since the 'data' object comes in as JSON). Normally, upon session.commit(), SQLAlchemy would convert the literal values to the proper representations of the model fields (in this case, to something like <EnumClass.TYPE_A: 0> instead of to 'TYPE_A', its literal representation). However, the patch method has to flush() the changes first in order to allow post-processors to make any changes. Unfortunately, the serializer is called before the sqlalchemy commit(), and the custom serializer fails because it expected an actual Enum but instead received a string representation of the field.
Stacktrace of the failing unit test:
self = <fields.EnumField(default=<marshmallow.missing>, attribute=None, validate=None...'type': u'Invalid input type.', 'must_be_string': 'Enum name must be string'})> value = 'HOME', attr = 'address_type', obj = <tests.test_updating.Address object at 0x1099f9c90> AttributeError: 'unicode' object has no attribute 'name' venv/lib/python2.7/site-packages/marshmallow_enum/__init__.py:74: AttributeError
Updated to first deserialize the partial document (request data passed to patch()) in order to force the conversion of the input enum value into its Enum representation so that setattr() in resources.py:_update_instance() sets the correct representation. This approach seems to solve the issue, but it causes most tests in test_updating.py to fail because the DefaultDeserializer's allow_client_generated_ids flag isn't set, and I cannot find a way to set it to True to avoid the ClientGeneratedIDNotAllowed
setup
An SQLalchemy model that has
problem
PATCH requests to update enum fields fail because the
resources.py:patch()
relies on directly setting the attributes of the sqlalchemy model instance to whatever values are provided by the request data dictionary (which are usually string/unicode representations of model field values since the 'data' object comes in as JSON). Normally, upon session.commit(), SQLAlchemy would convert the literal values to the proper representations of the model fields (in this case, to something like<EnumClass.TYPE_A: 0>
instead of to 'TYPE_A', its literal representation). However, the patch method has to flush() the changes first in order to allow post-processors to make any changes. Unfortunately, the serializer is called before the sqlalchemy commit(), and the custom serializer fails because it expected an actual Enum but instead received a string representation of the field. Stacktrace of the failing unit test:self = <fields.EnumField(default=<marshmallow.missing>, attribute=None, validate=None...'type': u'Invalid input type.', 'must_be_string': 'Enum name must be string'})> value = 'HOME', attr = 'address_type', obj = <tests.test_updating.Address object at 0x1099f9c90> AttributeError: 'unicode' object has no attribute 'name' venv/lib/python2.7/site-packages/marshmallow_enum/__init__.py:74: AttributeError
A more detailed background on the problem is discussed on this issue https://github.com/justanr/marshmallow_enum/issues/19
and demonstrated by this sample project: https://github.com/kiptoomm/flask_and_restless
attempted fix
Updated to first deserialize the partial document (request data passed to
patch()
) in order to force the conversion of the input enum value into its Enum representation so thatsetattr()
inresources.py:_update_instance()
sets the correct representation. This approach seems to solve the issue, but it causes most tests in test_updating.py to fail because the DefaultDeserializer's allow_client_generated_ids flag isn't set, and I cannot find a way to set it to True to avoid theClientGeneratedIDNotAllowed
Please see commit
af963701ee020f71ab2fe51331a35aac1c7e2d85
in the debug_issue_679 branch of my fork: https://github.com:kiptoomm/flask-restlessAny ideas on how to fix the exception, or advice on a cleaner approach?