我可以在我的Flask web应用程序中拥有2个user_loader方法吗?

问题描述 投票:1回答:2

在我的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)
python flask-sqlalchemy flask-login
2个回答
0
投票

@login_manager.user_loader 是一个装饰符,存在于 login_manager 类--它并不代表不同类型的用户(即 userworker)--所以你必须把它称为 user_loader 在这两种情况下。

但问题就在这里--你不能仅仅从用户id中知道你应该检索一个worker还是一个用户。由于worker实际上就是用户,所以不要有两个模型--将公共属性合并到一个模型中,并将worker相关的数据保留在一个单独的模型中,它们之间有关系(或者在用户模型上使它们可空,以保持简单)。

你已经有一个字段告诉你这个用户是普通用户还是工人,所以我会选择把它合并到一个单一模型中。你可以通过现在的机制来保持worker和job之间的引用(如果他们是用户,则设置workorder,如果他们是工人,则设置workrequest),或者你可以在JobLog和User表之间创建一个多对多的关系来代替--并使用User类型来确定他们是主管还是工人。


1
投票

与其这样,不如考虑一下应用模型继承模式。关于如何做到这一点,有一些很好的文档。此处. 这将有助于减少你的代码重复,简化用户加载逻辑。

从文档中可以看出。

当映射器被配置在继承关系中时,SQLAlchemy能够以多态方式加载元素,这意味着一个查询可以返回多种类型的对象。

这将允许的是,如果你的继承模式是 Person -> UserPerson -> 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,查询将返回一个 UserWorker 并表现得好像是由一张表来支持一样。

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

© www.soinside.com 2019 - 2024. All rights reserved.