python alembic升级时时间戳不应更改

tnkciper  于 2023-08-02  发布在  Python
关注(0)|答案(1)|浏览(84)

我刚刚在我的postgresql数据库上运行了一个alembic升级。“之前”和“之后”之间的差异表明,尽管只有一些表被修改,但所有表都被重写。更改仅发生在datetime列中,如下所示:

< 202   dac1d06a-e9e1-4739-a80c-9ae913e345c3    2023-05-23 12:05:58.972111+00   199 \N  139 \N  dut001  f   \N  script  initial commit  f
< 203   410ced4d-e2cf-4006-8cf0-f143f744f953    2023-05-23 12:05:58.980174+00   199 \N  141 201 duthandler  t   \N  script  initial commit  f
> 202   dac1d06a-e9e1-4739-a80c-9ae913e345c3    2023-05-23 14:05:58.972111+02   199 \N  139 \N  dut001  f   \N  script  initial commit  f
> 203   410ced4d-e2cf-4006-8cf0-f143f744f953    2023-05-23 14:05:58.980174+02   199 \N  141 201 duthandler  t   \N  script  initial commit  f

字符串
这些表最初是通过sqlalchemy生成的:

class MyClass(Base):
    __tablename__ = "alias_map_expanded"

    seq2 = Sequence(name="seq2")
    id = Column(
        BigInteger, sumo_seq2, server_default=seq2.next_value(), primary_key=True
    )
    uuid = Column(
        UUID(as_uuid=True), server_default=func.gen_random_uuid(), nullable=False
    )
    creation_date = Column(
        DateTime(timezone=True), server_default=func.current_timestamp(), nullable=False
    )
    ...


现在我已经读到了naive和non-naive的时间戳,并了解了如何在python中从一个时间戳到另一个时间戳,但我真的被为什么在升级过程中会发生这种情况以及如何避免时间戳一起改变的问题所困扰。
提前感谢!

aurhwmvo

aurhwmvo1#

chatGPT应答

您在alembic升级过程中遇到的问题似乎与PostgreSQL数据库中更新的时间戳有关。这种行为的原因可能是由于SQLAlchemy模型的定义方式以及alembic处理模型更改的方式。
问题是由为creation_date列提供的server_default属性引起的。当您定义server_default=func.current_timestamp()时,每当向表中插入新行时,它都会将列的默认值设置为当前时间戳。这是在插入时使用当前时间自动填充时间戳列的常用方法。
您在diff中看到的时间戳的差异是由于时区的更改。“之前”时间戳的时区为+00,而“之后”时间戳的时区为+02。这表示服务器的时区在两个时间戳之间发生了更改。
alembic升级重写所有表的问题与alembic跟踪并将更改应用于数据库模式的方式有关。当alembic检测到模型定义中的更改时,例如更改列默认值,它会生成必要的SQL命令来应用更改。在本例中,由于creation_date列有一个新的默认值,并且时区不同,alembic将生成SQL命令,用新的默认值更新表中所有现有的行。
为了避免在升级期间更改时间戳,您有几个选项:
1.删除creation_date列的server_default:如果不希望creation_date列自动填充当前时间戳,可以从列定义中删除server_default属性。这将阻止alembic生成SQL命令来更新现有行。

class MyClass(Base):
    __tablename__ = "alias_map_expanded"

    seq2 = Sequence(name="seq2")
    id = Column(BigInteger, sumo_seq2, server_default=seq2.next_value(), primary_key=True)
    uuid = Column(UUID(as_uuid=True), server_default=func.gen_random_uuid(), nullable=False)
    creation_date = Column(DateTime(timezone=True), nullable=False)

字符串
请注意,删除server_default将要求您在手动插入新行时为creation_date提供一个值。
1.对creation_date列使用server_onupdate:除了使用server_default,您还可以使用server_onupdate来仅在更新行时(而不是插入行时)自动更新creation_date列。

class MyClass(Base):
    __tablename__ = "alias_map_expanded"

    seq2 = Sequence(name="seq2")
    id = Column(BigInteger, sumo_seq2, server_default=seq2.next_value(), primary_key=True)
    uuid = Column(UUID(as_uuid=True), server_default=func.gen_random_uuid(), nullable=False)
    creation_date = Column(
        DateTime(timezone=True),
        server_default=func.current_timestamp(),
        server_onupdate=func.current_timestamp(),
        nullable=False,
    )
    ...


这样,creation_date列将仅在您修改行时自动更新,而不是在插入期间自动更新。
1.在插入过程中手动设置creation_date值:如果希望对creation_date列进行更多控制,并且不希望依赖于自动填充,则可以在向表中插入新行时手动设置creation_date值。

from datetime import datetime

class MyClass(Base):
    __tablename__ = "alias_map_expanded"

    seq2 = Sequence(name="seq2")
    id = Column(BigInteger, sumo_seq2, server_default=seq2.next_value(), primary_key=True)
    uuid = Column(UUID(as_uuid=True), server_default=func.gen_random_uuid(), nullable=False)
    creation_date = Column(DateTime(timezone=True), nullable=False)
    ...

插入特定creation_date行示例

new_row = MyClass(uuid=uuid_value, creation_date=datetime(2023, 5, 23, 12, 5, 58, 972111))
session.add(new_row)
session.commit()


选择最适合您要求的选项。删除server_default或使用server_onupdate可能会阻止升级过程中的自动更改,但也会更改creation_date列的行为,因此请仔细考虑您的选择的含义。

相关问题