Search code examples
pythonflasksqlalchemyflask-restfulmarshmallow

Nested Marshmallow and Sqlalchemy include children


I have a pivot (postgres)table that relates to 2 table. Using flask-marshmallow and sqlalchemy I want to fetch data from both tables from any of their marshmallow's schema. eg: Table1Schema().dump(table1_object).first: and get the Table1 records inner joined with Table2's data(Many=True): Below is my current code:

FYI: Im new to flask and the ORM world:

My Models:

class Permission(db.Model):
    __tablename__ = 'permission'
    permission_id = db.Column(db.Integer, primary_key=True)
    object = db.Column(db.String(70), nullable=False)

    def __init__(self, object):
        self.object = object


class Role(db.Model):
    __tablename__ = 'role'
    role_id = db.Column(db.Integer, primary_key = True)
    role_name = db.Column(db.String(70), nullable=False)
    role_permissions = db.relationship("RolePermission",backref='Role', lazy='dynamic')

    def __init__(self,role_name):
        self.role_name = role_name



class RolePermission(db.Model):
    __tablename__ = 'role_permission'
    role_permission_id = db.Column(db.Integer, primary_key=True)
    role_id = db.Column(db.Integer, db.ForeignKey('role.role_id', ondelete='CASCADE'), nullable =False)
    permission_id = db.Column(db.Integer, db.ForeignKey('permission.permission_id', ondelete='CASCADE'), nullable =False)

    def __init__(self,role_id,permission_id):
        self.role_id = role_id
        self.permission_id = permission_id

And my Schemas:

class RoleSchema(ma.Schema):
    role_id = fields.Integer(dump_only=True)
    role_name =  fields.String(required=True, validate=validate.Length(1))
    permissions = fields.Nested('RolePermissionSchema', many=True, only=('permission',))

    class Meta:
        model = Role
        fields = ('role_id', 'role_name', 'permissions')


class RolePermissionSchema(ma.Schema):
    role_permission_id = fields.Integer(dump_only=True)
    role_id = fields.Integer(required=True)
    permission_id = fields.Integer(required=True)
    role = fields.Nested('ROleSchema', many=False, only=('role_id', 'role_name',))
    permission = fields.Nested('PermissionSchema', many=False, only=('object', 'action',))




class PermissionSchema(ma.Schema):
    permission_id = fields.Integer(dump_only=True)
    object = fields.String(required=True, validate=validate.Length(1))
    role_permissions = fields.Nested('RolePermissionSchema', many=True, only=('role_permission_id', 'role_id',))
    class Meta:
        fields = ('object','action','role_permissions',)

serializer:

 role = Role.query.filter_by(role_name=data['role_name']).filter_by(status=data['status']).first()
role_schema.dump(role).data

I want to print a Role o object with the permissions[] object. However from the above all I am able to get is only the Role content. Below is the output :

{
        "role_name": "user",
        "status": true,
        "role_id": 4
    }

How do I get something like this:

{
    "role_name": "user",
    "status": true,
    "role_id": 4,
    "permissions":[{
         "object":"user",
         "action":"create"},
          ]
}

Solution

  • There are some naming issues, indicated here by comment lines #.

    class Role(db.Model):
       __tablename__ = 'role'
       role_id = db.Column(db.Integer, primary_key = True)
       role_name = db.Column(db.String(70), nullable=False)
       # This backref should probably be named role
       role_permissions = db.relationship("RolePermission",backref='Role', lazy='dynamic')
    
    class RoleSchema(ma.Schema):
        role_id = fields.Integer(dump_only=True)
        role_name =  fields.String(required=True, validate=validate.Length(1))
        # This does not correspond to role_permissions in class Role
        permissions = fields.Nested('RolePermissionSchema', many=True, only=('permission',))
    
        class Meta:
            model = Role
            fields = ('role_id', 'role_name', 'permissions')
    
    class RolePermissionSchema(ma.Schema):
       role_permission_id = fields.Integer(dump_only=True)
       role_id = fields.Integer(required=True)
       permission_id = fields.Integer(required=True)
       # Should be RoleSchema
       role = fields.Nested('ROleSchema', many=False, only=('role_id', 'role_name',))
       permission = fields.Nested('PermissionSchema', many=False, only=('object', 'action',))