支持多种方言的实体

huangapple go评论101阅读模式
英文:

Entity to support multiple dialects

问题

我有一个为PostgreSQL方言编写的SQLAlchemy实体,它使用了 server_default=func.clock_timestamp():

row_created = sa.Column('row_created_', sa.DateTime(timezone=True), server_default=func.clock_timestamp(), nullable=False)

我还需要在SQLite中使用它,但会抛出错误:

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) unknown function: clock_timestamp()

如何让这个在SQLAlchemy中工作?仅为SQLite定义 server_default?有条件地仅为特定方言添加整个列?以某种方式使 clock_timestamp() 在SQLite中可用(我不关心函数会执行什么,只要不失败)?

英文:

I have an SQLAlchemy entity written for PostgreSQL dialect and it uses server_default=func.clock_timestamp():

row_created = sa.Column('row_created_', sa.DateTime(timezone=True), server_default=func.clock_timestamp(), nullable=False)

I also need to use it with SQLite, which throws an error:

> sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) unknown function: clock_timestamp()

How do I make this work with SQLAlchemy? Define the server_default only for SQLite? Conditionally add entire column only for specific dialect? Somehow make clock_timestamp() known to SQLite (I don't care what the function will do, as long as it does not fail)?

答案1

得分: 1

你可以使用以下代码来设置服务器默认值:text("CURRENT_TIMESTAMP")

class TimeStamp(Base):
    __tablename__ = "timestamp"

    id: Mapped[int] = mapped_column(
        primary_key=True,
    )

    datetime_with_tz: Mapped[datetime] = mapped_column(
        types.DateTime(timezone=True),
        server_default=text("CURRENT_TIMESTAMP"),
    )

这将创建一个具有以下SQL的表格:

PostgresSQL:

CREATE TABLE timestamp (
        id SERIAL NOT NULL,
        datetime_with_tz TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
        PRIMARY KEY (id)
)

SQLite:

CREATE TABLE timestamp (
        id INTEGER NOT NULL,
        datetime_with_tz DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
        PRIMARY KEY (id)
)

如果你必须在PostgreSQL上使用clock_timestamp(),你可以将服务器默认值设置为:

server_default=text("CURRENT_TIMESTAMP") if use_sqlite else text("clock_timestamp()"),

PostgreSQL:

CREATE TABLE timestamp (
        id SERIAL NOT NULL,
        datetime_with_tz TIMESTAMP WITH TIME ZONE DEFAULT clock_timestamp() NOT NULL,
        PRIMARY KEY (id)
)

SQLite:

CREATE TABLE timestamp (
        id INTEGER NOT NULL,
        datetime_with_tz DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
        PRIMARY KEY (id)
)

你也可以使用"default",以使它在两个数据库上都能工作:

timestamp_auto = Annotated[
    datetime.datetime,
    mapped_column(
        default=datetime.datetime.now,
    ),
]

class TimeStamp(Base):
    __tablename__ = "timestamp"

    id: Mapped[int] = mapped_column(
        primary_key=True,
    )

    datetime_with_tz: Mapped[timestamp_auto] = mapped_column(
        types.DateTime(timezone=True),
    )
英文:

You can use: text("CURRENT_TIMESTAMP") for the server default:

class TimeStamp(Base):
    __tablename__ = "timestamp"

    id: Mapped[int] = mapped_column(
        primary_key=True,
    )

    datetime_with_tz: Mapped[datetime] = mapped_column(
        types.DateTime(timezone=True),
        server_default=text("CURRENT_TIMESTAMP"),
    )

This will create a table with the following SQL:

PostgresSQL:

CREATE TABLE timestamp (
        id SERIAL NOT NULL,
        datetime_with_tz TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
        PRIMARY KEY (id)
)

SQLite:

CREATE TABLE timestamp (
        id INTEGER NOT NULL,
        datetime_with_tz DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
        PRIMARY KEY (id)
)

If you must use clock_timestamp() on PostgreSQL, you can set server default
to:

server_default=text("CURRENT_TIMESTAMP") if use_sqlite else text("clock_timestamp()"),

postgres

CREATE TABLE timestamp (
        id SERIAL NOT NULL,
        datetime_with_tz TIMESTAMP WITH TIME ZONE DEFAULT clock_timestamp() NOT NULL,
        PRIMARY KEY (id)
)

sqlite

CREATE TABLE timestamp (
        id INTEGER NOT NULL,
        datetime_with_tz DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
        PRIMARY KEY (id)
)

You can also use "default" for it to work on both databases.

timestamp_auto = Annotated[
    datetime.datetime,
    mapped_column(
        default=datetime.datetime.now,
    ),
]


class TimeStamp(Base):
    __tablename__ = "timestamp"

    id: Mapped[int] = mapped_column(
        primary_key=True,
    )

    datetime_with_tz: Mapped[timestamp_auto] = mapped_column(
        types.DateTime(timezone=True),
    )

答案2

得分: 0

我从我的一位同事那里得到了一个提示,我最终采用了它,它在postgresql和sqlite都运行良好。

server_default=func.now()

据我所知,这与func.clock_timestamp()相同,但clock_timestamp()是特定于postgresql的,而now()受到多个数据库的支持。

英文:

I got a tip from a colleague of mine, which I ended up using and it works fine for both postgresql as well as sqlite.

server_default=func.now()

afaik it is the same as func.clock_timestamp(), but clock_timestamp() is postgresql-specific and now() is supoported by several DBs.

huangapple
  • 本文由 发表于 2023年7月28日 04:12:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76783114.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定