我是Flask Sqlalchemy的新手,我想声明多个模型并将它们彼此关联,我按照文档中的示例进行操作,但是我仍然遇到此错误
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
我不想将所有模型存储在一个文件中,因为项目可能会随着时间的流逝而变得越来越大,所以我创建了以下结构:
- models
--- __init__.py
--- User.py
--- Organization.py
--- ...
- manage.py
- app.py
我希望用户属于某个组织,并且该组织有很多用户,我也希望该组织对自己的自反关系具有一个可选字段,这是我尝试过的。
初始化 .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 bcrypt
class 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 fields
organization_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 = name
self.username = username
self.mobile = mobile
self.rule = rule
self.is_active = is_active
self.organization_id = organization_id
self.password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode()
def __repr__(self):
return "<id %s>" % self.id
class UserSchema(ma.SQLAlchemyAutoSchema):
rule = EnumField(RuleEnum, by_value=True)
class Meta:
exclude = ['password']
model = User
load_instance = True
Organization.py
from app import db, ma
import enum
from marshmallow_enum import EnumField
class 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 columns
parent = db.relationship('Organization', remote_side=id, backref='sub_organizations')
users = db.relationship('User', backref='organization')
# related fields
parent_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 = name
self.cr = cr
self.location = location
self.is_request_approved = is_request_approved
self.is_active = is_active
self.type = type
self.parent_id = parent_id
def __repr__(self):
return "<id %s>" % self.id
class OrganizationSchema(ma.SQLAlchemyAutoSchema):
type = EnumField(TypeEnum, by_value=True)
class Meta:
model = Organization
load_instance = True
关于迁移,我关注了一个博客文章,并使用此代码制作了manage.py
文件
manage.py
import os
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from app import app, db
app.config.from_object(os.environ['APP_SETTINGS'])
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
答案 0 :(得分:0)
为了将来参考,我通过在__init__.py
文件中安排import语句解决了该问题,因此,在关系中可能引用的任何类都应先导入,因此在我的情况下,我必须更改{{ 1}}文件到以下
__init__.py
这不是理想的解决方案,我敢肯定有更好的方法,因此欢迎其他任何/更好的方法供以后参考。