【问题标题】:How do I have Flask-SQLAlchemy with Postgres, have the primary key not reuse a deleted number?如何使用 Postgres 使用 Flask-SQLAlchemy,主键不重用已删除的数字?
【发布时间】:2020-10-24 15:23:33
【问题描述】:

我将 Flask-SQLAlchemy 与 Postgres 一起使用。我注意到当我删除一条记录时,下一条记录将重用那个人的 id,这不适合我的目的。另一个问题是这是默认行为。特别是他的SO question 讨论了幕后的sql。但是,当我在这个问题中测试解决方案时,它不起作用。事实上,postgres 并没有使用 SERIAL 作为主键。我不得不自己在pgadmin 中编辑它。其他程序中的解决方案提到使用Sequence,但没有显示序列的来源。

所以我希望这段代码:


class Test1(db.Model):
    __tablename__ = "test1"

    # id = ... this is what needs to change
    id = db.Column(db.Integer, primary_key=True)

如果记录 3 被删除并像这样创建另一个记录,则不会重用说 3:

i1 = Invoice()
db.session.add(i1)
i2 = Invoice()
db.session.add(i2)
i3 = Invoice()
db.session.add(i3)
db.session.commit()

invs = Invoice.query.all()
for i in invs:
    print(i.id)  # Should print 1,2,3

Invoice.query.filter(id=3).delete()  # no 3 now
db.session.commit()

i4 = Invoice()
db.session.add(i4)
db.session.commit()

invs = Invoice.query.all()
for i in invs:
    print(i.id)  # Should print 1,2,4

其他,据说使用autoincrement=False的解决方案。好的,但是我如何确定将 id 设置为的数字是多少?有没有办法在类中保存变量而不是列:

class Test2(db.Model)
    __tablename__ = 'test2'

    id = ...
    last_id = 3

    # code to set last_id when a record is deleted

编辑: 所以我可以(虽然我认为我不应该)使用 Python 来做到这一点。我认为这更清楚地说明了我正在尝试做的事情。

class Test1(db.Model):
    __tablename__ = "test1"

    # id = ... this is what needs to change
    id = db.Column(db.Integer, primary_key=True) 
    last_used_id = 30

    def __init__(self):
        self.id = last_used_id + 1
        self.last_used_id +=1

# Not sure if this somehow messes with SQLAlchemy / the db making the id first.

这将使任何新记录都不会触及已使用的 id。 但是,通过这种方法,我确实遇到了 Python 的类变量问题行为。见this SO question


未来的自我检查:请参阅@net 评论 here 的 UUID:

【问题讨论】:

  • 您使用的是什么版本的 postgres、psycopg2 和 sqlalchemy?

标签: python sqlalchemy flask-sqlalchemy


【解决方案1】:

您应该使用autoincrement=True。这将在您每次添加新行时自动增加 id。

class Test1(db.Model):
    __tablename__ = "test1"

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

由于性能问题,默认情况下 Postgres 不会重用 id。试图避免间隙或重复使用已删除的 ID 会产生可怕的性能问题。请参阅PostgreSQL wiki FAQ

您不需要跟踪 id。当您调用 db.session.add(i4)db.session.commit() 时,它会自动插入递增的 id。

【讨论】:

  • 查看我上面的代码块来测试这个。这在删除 id=4 然后创建新记录时不起作用。它会有 4
  • 我明白了。如果性能对您来说不是问题。考虑使用 uuid 版本 4 作为主键。这样它就永远是独一无二的。
  • 好的,我会调查的。这可能是解决方案。我想我应该更新我的问题。假设我有一张 id 为 10 的发票。我们通过电子邮件将其发送给客户。如果我们随后将其从系统中删除,它似乎将 11 重新编号为 10,也可能将 12 错误地设置为终点。所以我想这更像是一个诚信问题?这种变化是否表明还有其他解决方案需要研究。顺便说一句,我看到你是一个新用户。欢迎加入 SO 朋友!
  • 我没有退出理解这个问题。如果您删除一张发票,系统会再创建两张?系统是否会自动创建新发票来替换已删除的发票?如果我正确理解您的问题,也许您可​​以有另一个布尔列,例如valid。您可以切换valid 列,而不是删除发票。然后您的系统可以在发出发票提醒之前检查valid 列。感谢您的欢迎!
  • 查看我的更新。我用python解释它。对不起,我只是让自己在这一点上更加困惑:(
猜你喜欢
  • 2011-06-22
  • 2016-09-14
  • 2011-01-18
  • 2020-03-04
  • 1970-01-01
  • 2022-01-17
  • 2018-09-02
  • 2012-10-18
  • 2022-01-15
相关资源
最近更新 更多