Skip to content
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

PATCHing a model with Enum fields fails on serialization #679

Open
kiptoomm opened this issue Feb 2, 2018 · 0 comments
Open

PATCHing a model with Enum fields fails on serialization #679

kiptoomm opened this issue Feb 2, 2018 · 0 comments

Comments

@kiptoomm
Copy link

kiptoomm commented Feb 2, 2018

setup

An SQLalchemy model that has

  1. An Enum field
  2. A DateTime field to track updated_at timestamp on the model
  3. 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

A more detailed background on the problem is discussed on this issue
justanr/marshmallow_enum#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 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

Please see commit af963701ee020f71ab2fe51331a35aac1c7e2d85 in the debug_issue_679 branch of my fork: https://github.com:kiptoomm/flask-restless

Any ideas on how to fix the exception, or advice on a cleaner approach?

kiptoomm pushed a commit to kiptoomm/flask-restless that referenced this issue Feb 2, 2018
…rialization issue#679

- add dependencies for enum, marshmallow_enum serialization
- create marshmallow-based custom de/serialization to demonstrate
the issue
- add models, schema, serializers and a test case for updating enum fields. the test case fails as expected
- todo: apply a fix to the issue
kiptoomm pushed a commit to kiptoomm/flask-restless that referenced this issue Feb 2, 2018
…tance

- the idea is to deserialize the input fields into their actual
representations so that the setattr method of _update_instance() sets the real instance values and that custom serialization of enum fields works as expected
- this approach causes most unit tests in test_updating.py to fail :( due to the GeneratedIDNotAllowed exception. workaround?
- jfinkels#679
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant