Add created_at field to User and Item models and update endpoints (#2144)

This commit is contained in:
Alejandra
2026-01-23 16:18:22 +01:00
committed by GitHub
parent 2720308701
commit 3c1f7c4cdb
6 changed files with 78 additions and 2 deletions

View File

@@ -0,0 +1,31 @@
"""Add created_at to User and Item
Revision ID: fe56fa70289e
Revises: 1a31ce608336
Create Date: 2026-01-23 15:50:37.171462
"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes
# revision identifiers, used by Alembic.
revision = 'fe56fa70289e'
down_revision = '1a31ce608336'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('item', sa.Column('created_at', sa.DateTime(timezone=True), nullable=True))
op.add_column('user', sa.Column('created_at', sa.DateTime(timezone=True), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('user', 'created_at')
op.drop_column('item', 'created_at')
# ### end Alembic commands ###

View File

@@ -21,7 +21,9 @@ def read_items(
if current_user.is_superuser: if current_user.is_superuser:
count_statement = select(func.count()).select_from(Item) count_statement = select(func.count()).select_from(Item)
count = session.exec(count_statement).one() count = session.exec(count_statement).one()
statement = select(Item).offset(skip).limit(limit) statement = (
select(Item).order_by(Item.created_at.desc()).offset(skip).limit(limit)
)
items = session.exec(statement).all() items = session.exec(statement).all()
else: else:
count_statement = ( count_statement = (
@@ -33,6 +35,7 @@ def read_items(
statement = ( statement = (
select(Item) select(Item)
.where(Item.owner_id == current_user.id) .where(Item.owner_id == current_user.id)
.order_by(Item.created_at.desc())
.offset(skip) .offset(skip)
.limit(limit) .limit(limit)
) )

View File

@@ -42,7 +42,7 @@ def read_users(session: SessionDep, skip: int = 0, limit: int = 100) -> Any:
count_statement = select(func.count()).select_from(User) count_statement = select(func.count()).select_from(User)
count = session.exec(count_statement).one() count = session.exec(count_statement).one()
statement = select(User).offset(skip).limit(limit) statement = select(User).order_by(User.created_at.desc()).offset(skip).limit(limit)
users = session.exec(statement).all() users = session.exec(statement).all()
return UsersPublic(data=users, count=count) return UsersPublic(data=users, count=count)

View File

@@ -1,9 +1,15 @@
import uuid import uuid
from datetime import datetime, timezone
from pydantic import EmailStr from pydantic import EmailStr
from sqlalchemy import DateTime
from sqlmodel import Field, Relationship, SQLModel from sqlmodel import Field, Relationship, SQLModel
def get_datetime_utc() -> datetime:
return datetime.now(timezone.utc)
# Shared properties # Shared properties
class UserBase(SQLModel): class UserBase(SQLModel):
email: EmailStr = Field(unique=True, index=True, max_length=255) email: EmailStr = Field(unique=True, index=True, max_length=255)
@@ -43,12 +49,17 @@ class UpdatePassword(SQLModel):
class User(UserBase, table=True): class User(UserBase, table=True):
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
hashed_password: str hashed_password: str
created_at: datetime | None = Field(
default_factory=get_datetime_utc,
sa_type=DateTime(timezone=True), # type: ignore
)
items: list["Item"] = Relationship(back_populates="owner", cascade_delete=True) items: list["Item"] = Relationship(back_populates="owner", cascade_delete=True)
# Properties to return via API, id is always required # Properties to return via API, id is always required
class UserPublic(UserBase): class UserPublic(UserBase):
id: uuid.UUID id: uuid.UUID
created_at: datetime | None = None
class UsersPublic(SQLModel): class UsersPublic(SQLModel):
@@ -75,6 +86,10 @@ class ItemUpdate(ItemBase):
# Database model, database table inferred from class name # Database model, database table inferred from class name
class Item(ItemBase, table=True): class Item(ItemBase, table=True):
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
created_at: datetime | None = Field(
default_factory=get_datetime_utc,
sa_type=DateTime(timezone=True), # type: ignore
)
owner_id: uuid.UUID = Field( owner_id: uuid.UUID = Field(
foreign_key="user.id", nullable=False, ondelete="CASCADE" foreign_key="user.id", nullable=False, ondelete="CASCADE"
) )
@@ -85,6 +100,7 @@ class Item(ItemBase, table=True):
class ItemPublic(ItemBase): class ItemPublic(ItemBase):
id: uuid.UUID id: uuid.UUID
owner_id: uuid.UUID owner_id: uuid.UUID
created_at: datetime | None = None
class ItemsPublic(SQLModel): class ItemsPublic(SQLModel):

View File

@@ -126,6 +126,18 @@ export const ItemPublicSchema = {
type: 'string', type: 'string',
format: 'uuid', format: 'uuid',
title: 'Owner Id' title: 'Owner Id'
},
created_at: {
anyOf: [
{
type: 'string',
format: 'date-time'
},
{
type: 'null'
}
],
title: 'Created At'
} }
}, },
type: 'object', type: 'object',
@@ -352,6 +364,18 @@ export const UserPublicSchema = {
type: 'string', type: 'string',
format: 'uuid', format: 'uuid',
title: 'Id' title: 'Id'
},
created_at: {
anyOf: [
{
type: 'string',
format: 'date-time'
},
{
type: 'null'
}
],
title: 'Created At'
} }
}, },
type: 'object', type: 'object',

View File

@@ -23,6 +23,7 @@ export type ItemPublic = {
description?: (string | null); description?: (string | null);
id: string; id: string;
owner_id: string; owner_id: string;
created_at?: (string | null);
}; };
export type ItemsPublic = { export type ItemsPublic = {
@@ -75,6 +76,7 @@ export type UserPublic = {
is_superuser?: boolean; is_superuser?: boolean;
full_name?: (string | null); full_name?: (string | null);
id: string; id: string;
created_at?: (string | null);
}; };
export type UserRegister = { export type UserRegister = {