✨ Add created_at field to User and Item models and update endpoints (#2144)
This commit is contained in:
@@ -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 ###
|
||||||
@@ -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)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
Reference in New Issue
Block a user