Flask-SQLAlchemy中的一对一关系只能以一种方式工作

时间:2019-01-23 13:51:53

标签: flask sqlalchemy jinja2 flask-sqlalchemy

我在flask应用程序中有两个模型,它们形成一对一的关系,其中“ Staff”模型可以与一个“ User”关联。可以有“工作人员”而不让他们成为“用户”,但不能有“用户”而不是“工作人员”。

不幸的是,我遇到了第一个障碍。我正在尝试将模型合并到通过Jinja2模板化的HTML表中。该表应列出所有“工作人员”,并确定它们是否为“用户”。如果它们是“用户”,则应该确定它们是否处于活动状态。

这是我目前的模特:

class Staff(db.Model):
    __tablename__ = 'staff'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)
    job_title = db.Column(db.String(255), nullable=True)
    is_user = db.Column(db.Boolean, nullable=False, default=False)
    user = db.relationship('User', 
        backref=db.backref('staff', lazy=True))

    def __repr__(self):
        return f'Staff Member: {self.id}, {self.name}, {self.job_title}'


class User(db.Model, UserMixin):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), unique=True, nullable=False)
    image_file = db.Column(db.String(20), nullable=False, 
        default='default.jpg')
    password = db.Column(db.String(255), nullable=False)
    active = db.Column(db.Boolean, nullable=False, default=False)

    staff_id = db.Column(db.Integer, db.ForeignKey('staff.id'), 
       nullable=False)

    def __repr__(self):
        return f'User({self.name}, {self.email}, {self.image_file})'

这是Jinja2中的关系示例。该代码段按预期工作:

{% for user in users %}
<tr>
    <td>{{ user.staff.name }}</td>
    <td>{{ user.staff.job_title }}</td>
    <td>{{ user.email }}</td>
    {% if user.active == True %}
    <td>Yes</td>
    {% else %}
    <td>No</td>
    {% endif %}
{% endfor %}

但是,这段代码在遍历所有“工作人员”时试图获取“用户”详细信息的地方根本不起作用:

{% for staff in all_staff %}
    <tr>
        <td>{{ staff.name }}</td>
        <td>{{ staff.job_title }}</td>
    {% if staff.is_user == True %}
        {% if staff.user.active == True %}
        <td class="text-success">Yes (Active)</td>
        {% elif staff.user.active == False %}
        <td class="text-warning">Yes (Inactive)</td>
        {% endif %}
    {% elif staff.is_user == False %}
        <td class="text-danger">No</td>
    {% endif %}
{% endfor %}

虽然关系在第二个表格示例中以一种无效的方式起作用;除非staff.is_user == False语句为true,否则它根本不返回任何HTML代码。

我试图在'User'类中创建一个新的db.relationship。我也在两个类中一次尝试了db.relationship。我也尝试过在同一行上的Jinja2 if语句:

{% if staff.is_user == True and staff.user.active == True %}

但是这些都不起作用,并且我希望根据if语句的结果返回正确的html,通过“ Users”表引用时,我根本没有任何结果。 “员工桌。

我确定我缺少一些简单的东西,但我无法弄清楚。

有人可以看到我要去哪里吗?

1 个答案:

答案 0 :(得分:0)

事实证明,答案隐藏在Flask-SQLAlchemy docs的“一对五关系”部分中。为了引用一对一关系,您需要在该关系中设置uselist=False。听起来确实如此,它将连接作为标量而不是列表加载。

在从SQLAlchemy主文档中获取一些信息并且未正确加载关系中的backref时,我也犯了一个错误。在Flask-SQLAlchemy中,只需将其声明为字符串即可。在这种情况下,backref='staff'

此代码完全按预期工作:

class Staff(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True, nullable=False)
    job_title = db.Column(db.String(80))
    is_user = db.Column(db.Boolean, default=False)
    user = db.relationship('User', backref='staff', lazy=True, uselist=False)

    def __repr__(self):
        return f'Staff Member: {self.id}, {self.name}, {self.job_title}'


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), unique=True, nullable=False)
    active = db.Column(db.Boolean, nullable=False, default=False)
    staff_id = db.Column(db.Integer, db.ForeignKey('staff.id'), nullable=False)

    def __repr__(self):
        return f'User Account: {self.id}, {self.email}'