Skip to content

Commit b2a091d

Browse files
committed
posts model and schemas, user model updated to include posts relationship
1 parent 29885b9 commit b2a091d

File tree

5 files changed

+143
-24
lines changed

5 files changed

+143
-24
lines changed

src/app/models/post.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from typing import Optional
2+
import uuid as uuid_pkg
3+
from datetime import datetime
4+
5+
from sqlalchemy import String, DateTime, ForeignKey
6+
from sqlalchemy.orm import Mapped, mapped_column, relationship
7+
8+
from app.core.database import Base
9+
10+
class Post(Base):
11+
__tablename__ = "post"
12+
13+
id: Mapped[int] = mapped_column(
14+
"id", autoincrement=True, nullable=False, unique=True, primary_key=True, init=False
15+
)
16+
created_by_user_id: Mapped[int] = mapped_column(ForeignKey("user.id"))
17+
title: Mapped[str] = mapped_column(String(30))
18+
text: Mapped[str] = mapped_column(String(63206))
19+
media_url: Mapped[str] = mapped_column(String)
20+
21+
user: Mapped["User"] = relationship(back_populates="posts", lazy="selectin")
22+
23+
created_at: Mapped[datetime] = mapped_column(
24+
DateTime, default_factory=datetime.utcnow
25+
)
26+
updated_at: Mapped[Optional[datetime]] = mapped_column(default=None)
27+
deleted_at: Mapped[Optional[datetime]] = mapped_column(default=None)
28+
is_deleted: Mapped[bool] = mapped_column(default=False)

src/app/models/user.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
1-
from typing import Optional
1+
from typing import Optional, List
22
import uuid as uuid_pkg
33
from datetime import datetime
44

55
from sqlalchemy import String, DateTime
6-
from sqlalchemy.orm import Mapped, mapped_column
6+
from sqlalchemy.orm import Mapped, mapped_column, relationship
77

88
from app.core.database import Base
9+
from app.models.post import Post
910

1011
class User(Base):
1112
__tablename__ = "user"
1213

1314
id: Mapped[int] = mapped_column(
1415
"id", autoincrement=True, nullable=False, unique=True, primary_key=True, init=False
1516
)
17+
1618
name: Mapped[str] = mapped_column(String(30))
1719
username: Mapped[str] = mapped_column(String(20), unique=True, index=True)
1820
email: Mapped[str] = mapped_column(String(50), unique=True, index=True)
1921
hashed_password: Mapped[str] = mapped_column(String)
20-
22+
2123
profile_image_url: Mapped[str] = mapped_column(String, default="https://profileimageurl.com")
2224
uuid: Mapped[uuid_pkg.UUID] = mapped_column(
2325
default_factory=uuid_pkg.uuid4, primary_key=True, unique=True
@@ -29,3 +31,5 @@ class User(Base):
2931
deleted_at: Mapped[Optional[datetime]] = mapped_column(default=None)
3032
is_deleted: Mapped[bool] = mapped_column(default=False)
3133
is_superuser: Mapped[bool] = mapped_column(default=False)
34+
35+
posts: Mapped[List[Post]] = relationship(back_populates="user", cascade="all, delete", lazy="selectin", default_factory=list)

src/app/schemas/post.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
from typing import Annotated, Optional
2+
from datetime import datetime
3+
4+
from pydantic import BaseModel, Field, ConfigDict
5+
6+
from app.core.models import UUIDModel, TimestampModel, PersistentDeletion
7+
8+
class PostBase(BaseModel):
9+
title: Annotated[
10+
str,
11+
Field(min_length=2, max_length=30, examples=["This is my post"])
12+
]
13+
text: Annotated[
14+
str,
15+
Field(min_length=1, max_length=63206, examples=["This is the content of my post."])
16+
]
17+
18+
19+
class Post(TimestampModel, PostBase, UUIDModel, PersistentDeletion):
20+
media_url: Annotated[
21+
str | None,
22+
Field(
23+
pattern=r"^(https?|ftp)://[^\s/$.?#].[^\s]*$",
24+
examples=["https://www.postimageurl.com"],
25+
default=None
26+
),
27+
]
28+
created_by_user_id: int
29+
30+
31+
class PostRead(BaseModel):
32+
id: int
33+
title: Annotated[
34+
str,
35+
Field(min_length=2, max_length=30, examples=["This is my post"])
36+
]
37+
text: Annotated[
38+
str,
39+
Field(min_length=1, max_length=63206, examples=["This is the content of my post."])
40+
]
41+
media_url: Annotated[
42+
str | None,
43+
Field(
44+
pattern=r"^(https?|ftp)://[^\s/$.?#].[^\s]*$",
45+
examples=["https://www.postimageurl.com"],
46+
default=None
47+
),
48+
]
49+
created_by_user_id: int
50+
created_at: datetime
51+
52+
53+
class PostCreate(PostBase):
54+
model_config = ConfigDict(extra='forbid')
55+
56+
created_by_user_id: int
57+
media_url: str | None = None
58+
59+
60+
class PostUpdate(PostBase):
61+
model_config = ConfigDict(extra='forbid')
62+
63+
title: Annotated[
64+
str | None,
65+
Field(
66+
min_length=2,
67+
max_length=30,
68+
examples=["This is my updated post"],
69+
default=None
70+
)
71+
]
72+
text: Annotated[
73+
str | None,
74+
Field(
75+
min_length=1,
76+
max_length=63206,
77+
examples=["This is the updated content of my post."],
78+
default=None
79+
)
80+
]
81+
media_url: Annotated[
82+
str | None,
83+
Field(
84+
pattern=r"^(https?|ftp)://[^\s/$.?#].[^\s]*$",
85+
examples=["https://www.postimageurl.com"],
86+
default=None
87+
)
88+
]
89+
90+
91+
class PostUpdateInternal(PostUpdate):
92+
updated_at: datetime
93+
94+
95+
class PostDelete(BaseModel):
96+
model_config = ConfigDict(extra='forbid')
97+
98+
is_deleted: bool
99+
deleted_at: datetime

src/app/schemas/user.py

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,15 @@
88
class UserBase(BaseModel):
99
name: Annotated[
1010
str,
11-
Field(
12-
min_length=2, max_length=30, examples=["User Userson"]
13-
)
11+
Field(min_length=2, max_length=30, examples=["User Userson"])
1412
]
1513
username: Annotated[
1614
str,
17-
Field(
18-
min_length=2, max_length=20, pattern=r"^[a-z0-9]+$", examples=["userson"]
19-
)
15+
Field(min_length=2, max_length=20, pattern=r"^[a-z0-9]+$", examples=["userson"])
2016
]
2117
email: Annotated[
2218
EmailStr,
23-
Field(
24-
examples=["[email protected]"]
25-
)
19+
Field(examples=["[email protected]"])
2620
]
2721

2822

@@ -39,15 +33,11 @@ class UserRead(BaseModel):
3933
id: int
4034
name: Annotated[
4135
str,
42-
Field(
43-
min_length=2, max_length=30, examples=["User Userson"]
44-
)
36+
Field(min_length=2, max_length=30, examples=["User Userson"])
4537
]
4638
username: Annotated[
4739
str,
48-
Field(
49-
min_length=2, max_length=20, pattern=r"^[a-z0-9]+$", examples=["userson"]
50-
)
40+
Field(min_length=2, max_length=20, pattern=r"^[a-z0-9]+$", examples=["userson"])
5141
]
5242
profile_image_url: str
5343

@@ -57,9 +47,7 @@ class UserCreate(UserBase):
5747

5848
password: Annotated[
5949
str,
60-
Field(
61-
pattern=r"^.{8,}|[0-9]+|[A-Z]+|[a-z]+|[^a-zA-Z0-9]+$", examples=["Str1ngst!"]
62-
)
50+
Field(pattern=r"^.{8,}|[0-9]+|[A-Z]+|[a-z]+|[^a-zA-Z0-9]+$", examples=["Str1ngst!"])
6351
]
6452

6553

src/migrations/versions/ad940a8c0e9e_.py renamed to src/migrations/versions/211a8b0d0080_.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""empty message
22
3-
Revision ID: ad940a8c0e9e
3+
Revision ID: 211a8b0d0080
44
Revises:
5-
Create Date: 2023-09-28 23:19:52.423224
5+
Create Date: 2023-10-06 00:46:07.632040
66
77
"""
88
from typing import Sequence, Union
@@ -12,7 +12,7 @@
1212

1313

1414
# revision identifiers, used by Alembic.
15-
revision: str = 'ad940a8c0e9e'
15+
revision: str = '211a8b0d0080'
1616
down_revision: Union[str, None] = None
1717
branch_labels: Union[str, Sequence[str], None] = None
1818
depends_on: Union[str, Sequence[str], None] = None

0 commit comments

Comments
 (0)