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

Simple use case unsupported #26

Closed
sssilver opened this issue Sep 18, 2015 · 5 comments

Comments

@sssilver
Copy link

commented Sep 18, 2015

Hello,

Imagine a trivial use case in which we:

  • Read a model from the database
  • Serialize it into JSON
  • Receive updated JSON (from the web)
  • Deserialize it into an SQLAlchemy object
  • Persist the updated object in the database

Lets take a sample model:

class Group(rod.model.db.Model):
    __tablename__ = 'group'

    id = sqlalchemy.schema.Column(sqlalchemy.types.Integer, primary_key=True)
    title = sqlalchemy.schema.Column(sqlalchemy.types.String(100))

    teacher_id = sqlalchemy.schema.Column(sqlalchemy.types.Integer, sqlalchemy.schema.ForeignKey('staff.id'))
    teacher = sqlalchemy.orm.relationship(
        'Staff',  # References the Staff class below
        back_populates='groups'
    )

class Staff(rod.model.db.Model, rod.model.PersistentMixin):
    __tablename__ = 'staff'

    id = sqlalchemy.schema.Column(sqlalchemy.types.Integer, primary_key=True)

    # Personal Information
    name = sqlalchemy.schema.Column(sqlalchemy.types.String)
    groups = sqlalchemy.orm.relationship(
        'Group',
        back_populates='teacher'
    )

Since marshmallow-sqlalchemy converts relation fields to IDs between serialization and deserialization, the JSON string {"teacher": 1} when deserialized on Group becomes Group.teacher: Object<Teacher>, which looks like a new Teacher object, although it may be existing in the database.

The result, when you try to simply save the Group instance, is this:

FlushError: New instance <Group at 0x1088fd5d0> with identity key (<class 'rod.model.group.Group'>, (26,)) conflicts with persistent instance <Group at 0x1089c74d0>

@sssilver

This comment has been minimized.

Copy link
Author

commented Sep 18, 2015

The workaround is obviously to customize the schema for the 2 relation fields:

class GroupSchema(rod.model.BaseSchema):
    class Meta(rod.model.BaseSchema.Meta):
        model = rod.model.group.Group
        exclude = ['teacher']  # Get rid of the relation field that'll be converted to its ID

    # Add the actual ID field
    teacher_id = marshmallow_sqlalchemy.field_for(rod.model.group.Group, 'teacher_id')

Doing this makes the above scenario work by default, but then the question is, why isn't this the default schema configuration?

@sloria

This comment has been minimized.

Copy link
Member

commented Sep 19, 2015

Thanks for reporting, @sssilver. I'm currently focused on the marshmallow 2.0 final release, but I'm hoping to look into this issue more closely within the next week. Also, I'm always open to PRs =).

@sloria

This comment has been minimized.

Copy link
Member

commented Sep 27, 2015

Will #31 meet your use case?

@sssilver

This comment has been minimized.

Copy link
Author

commented Sep 27, 2015

Sounds like it would! The doc would need clarification between the ID fields (teacher_id, group_id) and the relation fields themselves (teacher, group).

@sloria

This comment has been minimized.

Copy link
Member

commented Sep 27, 2015

Done

@sloria sloria closed this Sep 27, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.