【问题标题】:Flask Foreign Key ConstraintFlask 外键约束
【发布时间】:2016-08-05 15:20:11
【问题描述】:

我在 Flask 中遇到外键问题。 我的模型如下:

Model.py

class User(db.Model):

    __tablename__ = "users"
    __table_args__ = {'extend_existing': True}
    user_id = db.Column(db.BigInteger, primary_key=True)
    # EDIT
    alerts = db.relationship('Alert', backref='user', lazy='dynamic')

    def __init__(self, user_id):
        self.user_id = user_id


class Alert(db.Model):

    __tablename__ = 'alert'
    __table_args__ = {'extend_existing': True}
    alert_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    user_id = db.Column(db.BigInteger, db.ForeignKey('users.user_id'), nullable=False)
    name = db.Column(db.String(ALERT_NAME_MAX_SIZE), nullable=False)

    def __init__(self, user_id, name):
        self.user_id = user_id
        self.name = name

我可以添加一些用户,例如

a = User(16)
b = User(17)
db.session.add(a)
db.session.add(b)
db.session.commit()

还有一些提醒:

c = Alert(16, 'test')
d = Alert(17, 'name_test')
db.session.add(c)
db.session.add(d)
db.session.commit()

外键有两个问题: 首先,当我尝试修改 user_id 警报时,即使 user_id 不在数据库中,我也可以这样做

 alert = Alert.query.get(1)
 alert.user_id = 1222 # not in the database
 db.session.commit()

并且我可以使用不在数据库中的 user_id 创建警报:

r = Alert(16223, 'test')
db.session.add(r)

我不明白为什么他们没有关系约束。 谢谢,

【问题讨论】:

  • 你在使用 sqlite 吗?
  • 我正在使用 SQLAlchemy
  • 是的,我可以看到,但是你的数据库是什么? SQLite 默认不强制使用外键,您必须使用特定的配置才能使其与 SQLAlchemy 一起使用。
  • 是的,但我没有找到关于它的好文档(或教程)
  • 我尝试使用 db.ForeignKeyConstraint(在我的代码中编辑)但没有改变

标签: python flask foreign-keys flask-sqlalchemy


【解决方案1】:

所以我找到了如何使用this stackoverflow question ,我找到了如何强制外键约束。

我只是在__init__.py 中添加此内容,并没有将任何内容更改为models.py

@event.listens_for(Engine, "connect")
    def _set_sqlite_pragma(dbapi_connection, connection_record):
         if isinstance(dbapi_connection, SQLite3Connection):
              cursor = dbapi_connection.cursor()
              cursor.execute("PRAGMA foreign_keys=ON;")
              cursor.close()

【讨论】:

    【解决方案2】:

    Alert 类的初始化代码中存在错误。在初始化警报时,您应该使用 backref 变量(即“用户”)而不是 user_id。以下代码应该可以工作。

    class User(db.Model):
    
        __tablename__ = "user"
        __table_args__ = {'extend_existing': True}
        user_id = db.Column(db.BigInteger, primary_key=True)
        alerts = db.relationship('Alert', backref='user', lazy='dynamic')
    
        def __init__(self, user_id):
            self.user_id = user_id
    
    
    class Alert(db.Model):
    
        __tablename__ = 'alert'
        alert_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        user_id = db.Column(db.BigInteger, db.ForeignKey('user.user_id'), nullable=False)
        name = db.Column(db.String(ALERT_NAME_MAX_SIZE), nullable=False)
    
        def __init__(self, user, name):
            self.user = user
            self.name = name
    

    它的工作原理如下:

    >>> a = User(7)
    >>> db.session.add(a)
    >>> db.session.commit()
    >>> b = Alert(a, 'test')
    >>> db.session.add(b)
    >>> db.session.commit()
    >>> alert = Alert.query.get(1)
    >>> alert.user_id
    7
    >>> alert.user
    <app.User object at 0x1045cb910>
    >>> alert.user.user_id
    7
    

    它不允许你分配像d = Alert(88, 'trdft')这样的变量

    我认为您应该阅读Flask SqlAlchemy's One-to-Many Relationships 了解更多详情。

    【讨论】:

    • 不起作用,我仍然可以使用不存在的 user_id 创建警报并使用不存在的 user_id 修改警报
    • 你好,谢谢,但它仍然不起作用,我可以创建 d = Alert(88, 'trdft')即使 88 不在用户数据库中
    • 它应该可以工作。 Alert(88, 'trdft') 应该抛出一个错误,因为 Alert 在初始化时需要 (, )。 88 不是 User 类的对象,它是一个整数,所以它应该抛出错误。你确定你改变了传递给 Alert 类的__init__ 的参数吗?您应该使用与 backref 变量相同的变量,即如果您在 User 类中有 alerts = db.relationship('Alert', backref='random_var', lazy='dynamic'),那么警报的 __init__ 将看起来像 def __init__(self, random_var, name)。
    • 抱歉我的错误,我没有更改__init__,但现在我遇到了不同的问题。我无法使用现有用户添加警报.....我可以使用新用户添加警报,并且将创建用户。当我尝试使用现有用户创建警报时,我得到:IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: users.user_id
    • 你是从新的数据库开始的吗?我的回答做了一些小的改动。我已将表名更改为“用户”,但之前忘记在外键声明db.ForeignKey('user.user_id') 中更改它。现在它应该可以完美运行了。如果没有,您能否通过编辑问题给出您的代码和确切的错误?并尝试使用新鲜的数据库。谢谢。
    【解决方案3】:

    如果您使用 SQLite,默认情况下不强制执行外键约束。有关如何启用此功能,请参阅文档中的 Enabling Foreign Key Support。

    【讨论】:

      猜你喜欢
      • 2016-02-18
      • 1970-01-01
      • 1970-01-01
      • 2014-01-17
      • 2017-04-20
      • 2018-03-05
      • 2013-01-30
      • 2014-01-16
      • 1970-01-01
      相关资源
      最近更新 更多