I'm new to Flask Sqlalchemy and I want to declare multiple models and relate them to each other, I followed the example in the documentation but I keep getting this error
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Organization->organizations,
expression 'User' failed to locate a name ('User').
If this is a class name,
consider adding this relationship()
to the <class 'models.Organization.Organization'>
class after both dependent classes have been defined
I don't want to store all my models in one files as the project might get bigger and bigger with time, so I've created the following structure:
- models
--- __init__.py
--- User.py
--- Organization.py
--- ...
- manage.py
- app.py
I want the user to belong to an Organization, and the Organization has many users, also I want the Organization to have an optional field for itself reflexive relationship, here is what I've tried.
init.py
from .Attachment import Attachment
from .Invoice import Invoice
from .Organization import Organization
from .Setting import Setting
from .Transaction import Transaction
from .User import User
User.py
from app import db, ma
from marshmallow_enum import EnumField
import enum
import bcryptclass RuleEnum(enum.Enum):admin = 'admin',collector = 'collector'retailer = 'retailer'vendor = 'vendor'vendor_admin = 'vendor_admin'class User(db.Model):__tablename__ = 'users'id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(), nullable=False)mobile = db.Column(db.String(), nullable=False)username = db.Column(db.String(), unique=True, nullable=False)password = db.Column(db.TEXT(), nullable=False)is_active = db.Column(db.Boolean(), default=False)rule = db.Column(db.Enum(RuleEnum), nullable=False)created_on = db.Column(db.DateTime, server_default=db.func.now())updated_on = db.Column(db.DateTime, server_default=db.func.now(), server_onupdate=db.func.now())# relations#related fieldsorganization_id = db.Column(db.Integer, db.ForeignKey('organizations.id'), nullable=True)def __init__(self,name,username,mobile,password,rule,is_active,organization_id = None):self.name = nameself.username = usernameself.mobile = mobileself.rule = ruleself.is_active = is_activeself.organization_id = organization_idself.password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode()def __repr__(self):return "<id %s>" % self.idclass UserSchema(ma.SQLAlchemyAutoSchema):rule = EnumField(RuleEnum, by_value=True)class Meta:exclude = ['password']model = Userload_instance = True
Organization.py
from app import db, ma
import enum
from marshmallow_enum import EnumFieldclass TypeEnum(enum.Enum):vendor = 'vendor'retailer = 'retailer'class Organization(db.Model):__tablename__ = 'organizations'id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String())cr = db.Column(db.String(), unique=True)location = db.Column(db.String())is_request_approved = db.Column(db.Boolean(), default=False)is_active = db.Column(db.Boolean(), default=False)type = db.Column(db.Enum(TypeEnum))created_on = db.Column(db.DateTime, server_default=db.func.now())updated_on = db.Column(db.DateTime, server_default=db.func.now(), server_onupdate=db.func.now())# relations# virtual columnsparent = db.relationship('Organization', remote_side=id, backref='sub_organizations')users = db.relationship('User', backref='organization')# related fieldsparent_id = db.Column(db.Integer, db.ForeignKey('organizations.id'), nullable=True)def __init__(self,name,cr,location,is_request_approved,is_active,type,parent_id = None):self.name = nameself.cr = crself.location = locationself.is_request_approved = is_request_approvedself.is_active = is_activeself.type = typeself.parent_id = parent_iddef __repr__(self):return "<id %s>" % self.idclass OrganizationSchema(ma.SQLAlchemyAutoSchema):type = EnumField(TypeEnum, by_value=True)class Meta:model = Organizationload_instance = True
Regarding the migrations I've followed a blog post and made the manage.py
file with this code
manage.py
import osfrom flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommandfrom app import app, dbapp.config.from_object(os.environ['APP_SETTINGS'])
migrate = Migrate(app, db)
manager = Manager(app)manager.add_command('db', MigrateCommand)if __name__ == '__main__':manager.run()