← full-stack-fastapi-template  /  backend/app/models.py

1
import uuid
2
from datetime import datetime, timezone
3
4
from pydantic import EmailStr
5
from sqlalchemy import DateTime
6
from sqlmodel import Field, Relationship, SQLModel
7
8
9
def get_datetime_utc() -> datetime:
10
    return datetime.now(timezone.utc)
11
12
13
# Shared properties
14
class UserBase(SQLModel):
15
    email: EmailStr = Field(unique=True, index=True, max_length=255)
16
    is_active: bool = True
17
    is_superuser: bool = False
18
    full_name: str | None = Field(default=None, max_length=255)
19
20
21
# Properties to receive via API on creation
22
class UserCreate(UserBase):
23
    password: str = Field(min_length=8, max_length=128)
24
25
26
class UserRegister(SQLModel):
27
    email: EmailStr = Field(max_length=255)
28
    password: str = Field(min_length=8, max_length=128)
29
    full_name: str | None = Field(default=None, max_length=255)
30
31
32
# Properties to receive via API on update, all are optional
33
class UserUpdate(UserBase):
34
    email: EmailStr | None = Field(default=None, max_length=255)  # type: ignore[assignment]
35
    password: str | None = Field(default=None, min_length=8, max_length=128)
36
37
38
class UserUpdateMe(SQLModel):
39
    full_name: str | None = Field(default=None, max_length=255)
40
    email: EmailStr | None = Field(default=None, max_length=255)
41
42
43
class UpdatePassword(SQLModel):
44
    current_password: str = Field(min_length=8, max_length=128)
45
    new_password: str = Field(min_length=8, max_length=128)
46
47
48
# Database model, database table inferred from class name
49
class User(UserBase, table=True):
50
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
51
    hashed_password: str
52
    created_at: datetime | None = Field(
53
        default_factory=get_datetime_utc,
54
        sa_type=DateTime(timezone=True),  # type: ignore
55
    )
56
    items: list["Item"] = Relationship(back_populates="owner", cascade_delete=True)
57
58
59
# Properties to return via API, id is always required
60
class UserPublic(UserBase):
61
    id: uuid.UUID
62
    created_at: datetime | None = None
63
64
65
class UsersPublic(SQLModel):
66
    data: list[UserPublic]
67
    count: int
68
69
70
# Shared properties
71
class ItemBase(SQLModel):
72
    title: str = Field(min_length=1, max_length=255)
73
    description: str | None = Field(default=None, max_length=255)
74
75
76
# Properties to receive on item creation
77
class ItemCreate(ItemBase):
78
    pass
79
80
81
# Properties to receive on item update
82
class ItemUpdate(ItemBase):
83
    title: str | None = Field(default=None, min_length=1, max_length=255)  # type: ignore[assignment]
84
85
86
# Database model, database table inferred from class name
87
class Item(ItemBase, table=True):
88
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
89
    created_at: datetime | None = Field(
90
        default_factory=get_datetime_utc,
91
        sa_type=DateTime(timezone=True),  # type: ignore
92
    )
93
    owner_id: uuid.UUID = Field(
94
        foreign_key="user.id", nullable=False, ondelete="CASCADE"
95
    )
96
    owner: User | None = Relationship(back_populates="items")
97
98
99
# Properties to return via API, id is always required
100
class ItemPublic(ItemBase):
101
    id: uuid.UUID
102
    owner_id: uuid.UUID
103
    created_at: datetime | None = None
104
105
106
class ItemsPublic(SQLModel):
107
    data: list[ItemPublic]
108
    count: int
109
110
111
# Generic message
112
class Message(SQLModel):
113
    message: str
114
115
116
# JSON payload containing access token
117
class Token(SQLModel):
118
    access_token: str
119
    token_type: str = "bearer"
120
121
122
# Contents of JWT token
123
class TokenPayload(SQLModel):
124
    sub: str | None = None
125
126
127
class NewPassword(SQLModel):
128
    token: str
129
    new_password: str = Field(min_length=8, max_length=128)
130