无法使用 flask-sqlalchemy 创建自动递增主键

Posted

技术标签:

【中文标题】无法使用 flask-sqlalchemy 创建自动递增主键【英文标题】:unable to create autoincrementing primary key with flask-sqlalchemy 【发布时间】:2014-01-17 20:32:18 【问题描述】:

我希望我的模型的主键是一个自动递增的整数。这是我的模型的样子

class Region(db.Model):
    __tablename__ = 'regions'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(100))
    parent_id = db.Column(db.Integer, db.ForeignKey('regions.id'))
    parent = db.relationship('Region', remote_side=id, primaryjoin=('Region.parent_id==Region.id'), backref='sub-regions')
    created_at = db.Column(db.DateTime, default=db.func.now())
    deleted_at = db.Column(db.DateTime)

上面的代码创建了我的表,但没有使id自动递增。因此,如果在我的插入查询中我错过了 id 字段,它会给我这个错误

错误:“id”列中的空值违反非空约束

所以我将id 声明更改为如下所示

id = db.Column(db.Integer, db.Sequence('seq_reg_id', start=1, increment=1),
               primary_key=True)

还是同样的错误。上面的代码有什么问题?

【问题讨论】:

你能贴出你用来创建区域对象的代码吗? 我正在尝试像INSERT INTO regions(name, ) ...这样的普通sql插入 您的原始代码应该可以工作。您确定您实际上是在使用 SQLAlchemy 创建表吗?您确定您正在查看正确的数据库吗?在 SQLAlchemy 中尝试configuring logging,看看使用 SQLAlchemy 创建表时输出的 SQL 是什么。 非常好。你的代码是我的解决方案。我一直在寻找如何使用 Oracle 的序列,直到你的帖子。谢谢! 还是同样的错误 【参考方案1】:

您不能在列定义中添加“autoincrement”标志,而且在 __table__name 之后添加“__table__args”属性。 像这样的:

    __tablename__ = 'table-name'
    __table_args__ = 'sqlite_autoincrement': True -> This adds autoincrement to your primary key.

试试吧,我希望这对你有用;)!

【讨论】:

【参考方案2】:

我在模型类上声明复合键时遇到了这个问题。

如果您想要一个复合键的自动递增 id 字段(即超过 1 个 db.Column(..) 定义和 primary_key=True,那么添加 autoincrement=True 为我解决了这个问题。

class S3Object(db.Model):
    __tablename__ = 's3_object'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)

    # composite keys
    bucket_name = db.Column(db.String(), primary_key=True)
    key = db.Column(db.String(), primary_key=True)

所以上面关于不需要autoincrement=True 的陈述应该是:

你甚至不需要autoincrement=True,因为 SQLAlchemy 会自动设置第一个 未将 FK 标记为 autoincrement=True 的整数 PK 列除非您定义的复合键包含多个 primary_key=True

【讨论】:

【参考方案3】:

即使没有设置 autoincrement=True 标志,默认情况下您的 id 也会自动递增。

所以使用没有什么问题

id = db.Column(db.Integer, primary_key=True, autoincrement=True)

您遇到的错误是由于尝试使用 id 属性填充表。您的插入查询在任何时候都不应包含 id 属性,否则您将收到该错误。

【讨论】:

【参考方案4】:

即使添加了autoincrement=True,我也遇到了同样的错误。

问题是我已经创建了迁移。所以我降级到之前的迁移,删除迁移,重新创建迁移并升级。

然后错误就消失了。

希望它可以帮助坚持这一点的人。

结束:添加autoincrement=True,并确保您的迁移得到更新和应用。

【讨论】:

【参考方案5】:

所以我遇到了一个问题,即我的 SQLite 表没有自动递增主键。我有一个稍微复杂的用例,我想在生产中使用 postgres,但使用 sqlite 进行测试,以便在持续部署时让生活更轻松。

事实证明 SQLite 不喜欢定义为 BigIntegers 的列,并且为了递增工作,它们应该设置为 Integers。值得注意的是,SQLAlchemy 可以使用 with_variant 函数按如下方式处理这种情况。认为这可能对某人有用:

id = db.Column(db.BigInteger().with_variant(db.Integer, "sqlite"), primary_key=True)

更多详情在这里https://docs.sqlalchemy.org/en/13/dialects/sqlite.html

【讨论】:

我在这里遇到同样的问题(prod=postgresql,testing=sqlite),但我所有的主键已经是整数。有点荒谬,但这仍然解决了它:id = db.Column(db.Integer().with_variant(Integer, "sqlite"), primary_key=True) 这是解决我的问题的最佳答案(postgresql->production,sqlite->test)。谢谢【参考方案6】:

我认为你一旦设置就不需要自动增量,

id = db.Column(db.Integer , primary_key=True , autoincrement=True)

我认为应该是,

id = db.Column(db.Integer , primary_key=True)

它将为您提供您所寻找的独特性。

【讨论】:

【参考方案7】:

上面的代码没有错。实际上,您甚至不需要autoincrement=Truedb.Sequence('seq_reg_id', start=1, increment=1),,因为SQLAlchemy 会自动将第一个未标记为FK 的Integer PK 列设置为autoincrement=True

在这里,我根据您的设置整理了一个工作设置。 SQLAlechemy 的 ORM 将负责生成 id 并用它们填充对象如果您使用您定义的基于 Declarative Base 的类来创建对象的实例。

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.debug = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:password@localhost/testdb'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)

class Region(db.Model):
    __tablename__ = 'regions'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))

db.drop_all()
db.create_all()

region = Region(name='Over Yonder Thar')
app.logger.info(region.id) # currently None, before persistence

db.session.add(region)
db.session.commit()
app.logger.info(region.id) # gets assigned an id of 1 after being persisted

region2 = Region(name='Yet Another Up Yar')
db.session.add(region2)
db.session.commit()
app.logger.info(region2.id) # and 2

if __name__ == '__main__':
    app.run(port=9001)

【讨论】:

我也有类似的情况。假设现在表中有 4 条记录,从 id 1 到 4。当我执行 db.session.query(Table_name).delete() db.session.commit() 然后如果我再次执行 db.session.add() 以添加新记录,下一条记录的 id 为 5。因为我的表现在是空的,我希望我的新记录现在再次从 1 开始获得一个 id。我该怎么做? 我试图找出一个不同但相关的问题,即如何根据 model.py 填充我的数据库,并发现 db.drop_all()db.create_all() 是超级有帮助。谢谢。 这也适用于 Oracle 数据库,您必须在其中安装/设置一个序列来处理 AUTOINCREMENT 主键处理。 这不起作用`“module_id”列中的空值违反了非空约束细节:失败的行包含` @qre0ct 这对于关系数据库实际上毫无意义,因为您将无法同时添加/删除多行。每次更改 ID 时,您的数据库引擎都必须检查您的索引是否一切正常。 ID 列应该没有意义。当然,这条规则也有一些例外。如果您担心 ID 用完,只需分配 BigInt 并永远忘记它。

以上是关于无法使用 flask-sqlalchemy 创建自动递增主键的主要内容,如果未能解决你的问题,请参考以下文章

使用 Flask-SQLAlchemy 在 Alembic 自动生成迁移中未检测到任何变化

AttributeError:使用flask-sqlalchemy连接到sqlite数据库时无法设置属性

Flask-Sqlalchemy 使用 postgres 创建视图

Flask-SQLAlchemy使用方法

flask-sqlalchemy

flask-sqlalchemy使用命令创建数据库