我的 Flask Web 应用程序中可以有 2 个 user_loader 方法吗

Can I have 2 user_loader methods in my Flask web application

在我的 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_loaderlogin_manager class 中的装饰器 - 它不代表不同类型的用户(即 userworker) -所以在这两种情况下您都必须将其称为 user_loader

但这就是问题所在 - 您无法知道是应该仅从用户 ID 检索工作人员还是用户。由于工作者实际上是用户,所以不要有两个模型——将公共属性合并到一个模型中,并将与工作者相关的数据保存在一个单独的模型中,并在它们之间建立关系(或者使它们在用户模型上可以为空以使其更简单).

你已经有一个字段告诉你用户是普通用户还是工作人员,所以我会把它合并到一个模型中。您可以通过与今天相同的机制保持工作人员和工作之间的引用(如果他们是用户则设置工作订单,如果他们是工作人员则设置工作请求)或者您可以在 JobLog 之间创建多对多关系和用户 table - 并使用用户类型来确定他们是主管还是工人。

取而代之的是,考虑应用模型继承模式。关于如何做到这一点有一些很好的文档 here。这将有助于减少您的代码重复并简化用户加载逻辑。

来自文档:

When mappers are configured in an inheritance relationship, SQLAlchemy has the ability to load elements polymorphically, meaning that a single query can return objects of multiple types.

如果您的继承模式是 Person -> UserPerson -> Worker,那么您的用户加载器可能如下所示:

@login_manager.user_loader
def user_loader(id):
    return Person.query.get(id)

该加载程序将 return 层次结构中的任何类型,具体取决于与 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'
    }

在该代码中,每个模型都由其自己的 table 表示,代表其自身与基本人物模型之间的差异。当您加载 Person 的实例时,查询将 return 为 UserWorker,并且表现得好像它由单个 table 支持。

我没有测试代码,所以如果有任何错误,请随时编辑。