Search code examples
flaskflask-sqlalchemymarshmallow

Flask-sqlalchemy-Marshmallow nesting Schema not working


Basically what i want to do is, join 2 tables 'users' & 'company' and get the users with their relevant company details .

this is the user model:

class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
firstname = db.Column(db.String(10), nullable=False)
lastname = db.Column(db.String(25), nullable=False)
username = db.Column(db.String(250), nullable=False)
email = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(250), nullable=False)
isPasswordReset = db.Column(db.Boolean, nullable=False)
companyId = db.Column(db.Integer, db.ForeignKey(
    'company.id'), nullable=True)

and this is the schema

class UserSchema(ma.Schema):
id = fields.Integer()
firstname = fields.String(required=True)
lastname = fields.String(required=True)
username = fields.String(required=True)
email = fields.String(required=True)
password = fields.String(required=True)
isPasswordReset = fields.Boolean(required=True)
companyId = fields.Integer()
company_name = fields.Nested(CompanySchema)

This is the company model:

class Company(db.Model):
__tablename__ = 'company'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
companyName = db.Column(db.String(100), nullable=True)
companyCode = db.Column(db.String(20), nullable=True)
companyTheme = db.Column(db.String(300), nullable=True)

this is the company schema:

class CompanySchema(ma.Schema):
id = fields.Integer()
companyName = fields.String(required=True)
companyCode = fields.String(required=True)
companyTheme = fields.String(required=True)

and this is the resource-user.py :

users_schema = UserSchema(many=True)
user_schema = UserSchema()

class UsersResource(Resource):
def get(self):
users = db.session.query(User.firstname, Company.companyName).join(
Company, User.companyId == Company.id).all()
if users:
results = users_schema.dump(users).data
return {'status': 'success', 'message': json.dumps(results, default=str)}, 200

and this is output i get :

{ "status": "success", "message": "[{\"firstname\": \"abc\"}, {\"firstname\": \"xyz\"}]" }

only user table are shown, not from company table.i have followed a lot of tutorial and stuff for hours. but still couldn't fix it.i'm new to flask and sqlalchemy. please does anyone knows how to correct this?


Solution

  • At first you need to declare relationship object in your sqlalchemy model:

    class User(db.Model):
        __tablename__ = 'user'
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        firstname = db.Column(db.String(10), nullable=False)
        lastname = db.Column(db.String(25), nullable=False)
        username = db.Column(db.String(250), nullable=False)
        email = db.Column(db.String(100), nullable=False)
        password = db.Column(db.String(250), nullable=False)
        isPasswordReset = db.Column(db.Boolean, nullable=False)
        companyId = db.Column(db.Integer, db.ForeignKey(
                             'company.id'), nullable=True)
        company = db.relationship("Company", backref="parents")  # <--
    

    Then in the user schema declare field that represents that object:

    class UserSchema(ma.Schema):
        id = fields.Integer()
        firstname = fields.String(required=True)
        lastname = fields.String(required=True)
        username = fields.String(required=True)
        email = fields.String(required=True)
        password = fields.String(required=True)
        isPasswordReset = fields.Boolean(required=True)
        companyId = fields.Integer()
        company = fields.Nested(CompanySchema) # <-- 
    

    Please notice, that field names must be the same (or you can use attribute argument).

    While querying you could simply do:

    user_schema = UserSchema()
    users = User.query.all()
    results = users_schema.dump(users).data
    return {'status': 'success', 'message': json.dumps(results, default=str)}, 200
    

    (or return users_schema.dump(users) for testing purposes)

    After all you should get output like this:

    {
    id: 'something',
    firstname: 'something',
    lastname: 'something',
    username: 'something',
    email: 'something',
    password: 'something',
    isPasswordReset: 'something',
    company : {
               id: 'something',
               companyName: 'something',
               companyCode: 'something',
               companyTheme: 'something',
              }
    }
    

    Does this cover your needs?