I believe that the accepted answer is for SQLAlchemy 1.4, and 2.0 has quite a different syntax, so I'm adding this answer for 2.x:
from typing import Optional
from datetime import datetime
from sqlalchemy import BigInteger, ForeignKey, Identity, text, Text, TIMESTAMP
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.dialects.postgresql import JSONB
class Post(Base):
__tablename__ = "posts"
id: Mapped[int] = mapped_column(
BigInteger, Identity(always=True), primary_key=True
)
user_id: Mapped[Optional[UUID]] = mapped_column(ForeignKey("users.id"))
title: Mapped[str] = mapped_column(Text, nullable=False)
content: Mapped[str] = mapped_column(Text, nullable=False)
cache: Mapped[Optional[dict]] = mapped_column(JSONB)
created_at: Mapped[datetime] = mapped_column(
TIMESTAMP(timezone=True),
nullable=False,
server_default=text("CURRENT_TIMESTAMP")
)
Which produces ...
CREATE TABLE posts (
id BIGINT GENERATED ALWAYS AS IDENTITY,
user_id UUID,
title TEXT NOT NULL,
content TEXT NOT NULL,
cache JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id),
And I believe this generally conforms to Postgres recommendations.
onupdate.onupdate=func.utc_timestamp()has no effect on a Postgres backend (it might in others)userstable above