在我的web应用程序中,用户和工人可以登录,我有2个不同的模型。然而,当我试图为工人模型创建一个user_loader方法时,我收到了错误信息,即
以下是我的代码
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@login_manager.worker_loader
def load_worker(worker_id):
return Worker.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
fname = db.Column(db.String(30), nullable=False)
lname = db.Column(db.String(30), nullable=False)
phone = db.Column(db.String(11), unique=True, nullable=False)
email = db.Column(db.String(25), unique=True, nullable=False)
location = db.Column(db.String(15), nullable=False)
password = db.Column(db.String(60), nullable=False)
mode = db.Column(db.String(10), nullable=False, default='User')
address = db.relationship('Address', backref='user_address', lazy=True)
workorder = db.relationship('JobLog', backref='order', lazy=True)
class Worker(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
fname = db.Column(db.String(30), nullable=False)
lname = db.Column(db.String(30), nullable=False)
phone = db.Column(db.String(11), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
location = db.Column(db.String(15), nullable=False)
job = db.Column(db.String(20), nullable=False)
description = db.Column(db.Text, nullable=False,
default='Insert your personal description here')
image = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
mode = db.Column(db.String(10), nullable=False, default='Worker')
active = db.Column(db.Boolean, nullable=False, default=False)
workrequest = db.relationship('JobLog', backref='request', lazy=True)
@login_manager.user_loader
是一个装饰符,存在于 login_manager
类--它并不代表不同类型的用户(即 user
和 worker
)--所以你必须把它称为 user_loader
在这两种情况下。
但问题就在这里--你不能仅仅从用户id中知道你应该检索一个worker还是一个用户。由于worker实际上就是用户,所以不要有两个模型--将公共属性合并到一个模型中,并将worker相关的数据保留在一个单独的模型中,它们之间有关系(或者在用户模型上使它们可空,以保持简单)。
你已经有一个字段告诉你这个用户是普通用户还是工人,所以我会选择把它合并到一个单一模型中。你可以通过现在的机制来保持worker和job之间的引用(如果他们是用户,则设置workorder,如果他们是工人,则设置workrequest),或者你可以在JobLog和User表之间创建一个多对多的关系来代替--并使用User类型来确定他们是主管还是工人。
与其这样,不如考虑一下应用模型继承模式。关于如何做到这一点,有一些很好的文档。此处. 这将有助于减少你的代码重复,简化用户加载逻辑。
从文档中可以看出。
当映射器被配置在继承关系中时,SQLAlchemy能够以多态方式加载元素,这意味着一个查询可以返回多种类型的对象。
这将允许的是,如果你的继承模式是 Person -> User
和 Person -> Worker
那么你的用户加载器可以是这样的。
@login_manager.user_loader
def user_loader(id):
return Person.query.get(id)
然后,加载器将根据id所关联的类型,返回层次结构中的任何类型。
一个示例模式可以是这样的:在该代码中,每个模型都由它自己的表来表示。
class Person(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
fname = db.Column(db.String(30), nullable=False)
lname = db.Column(db.String(30), nullable=False)
phone = db.Column(db.String(11), unique=True, nullable=False)
email = db.Column(db.String(25), unique=True, nullable=False)
location = db.Column(db.String(15), nullable=False)
password = db.Column(db.String(60), nullable=False)
mode = db.Column(db.String(10), nullable=False, default='User')
type = Column(String(20)) # this is the discriminator column
__mapper_args__ = {
'polymorphic_on':type,
}
class User(Person):
id = db.Column(db.Integer, db.ForeignKey('person.id'), primary_key=True)
address = db.relationship('Address', backref='user_address', lazy=True)
workorder = db.relationship('JobLog', backref='order', lazy=True)
__mapper_args__ = {
'polymorphic_identity':'user'
}
class Engineer(Person):
id = db.Column(db.Integer, db.ForeignKey('person.id'), primary_key=True)
job = db.Column(db.String(20), nullable=False)
description = db.Column(db.Text, nullable=False,
default='Insert your personal description here')
image = db.Column(db.String(20), nullable=False, default='default.jpg')
active = db.Column(db.Boolean, nullable=False, default=False)
workrequest = db.relationship('JobLog', backref='request', lazy=True)
__mapper_args__ = {
'polymorphic_identity':'worker'
}
在那段代码中,每个模型都由它自己的表来表示 它代表了它自己和基础人模型之间的区别。当你加载一个 Person
,查询将返回一个 User
或 Worker
并表现得好像是由一张表来支持一样。
我还没有测试代码,如果有任何错误,请随时编辑。