Skip to content

Commit 339c700

Browse files
committed
add Movie model and schema
1 parent b487ef9 commit 339c700

File tree

12 files changed

+254
-55
lines changed

12 files changed

+254
-55
lines changed

examples/api_for_sqlalchemy/models/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from examples.api_for_sqlalchemy.models.age_rating import AgeRating
12
from examples.api_for_sqlalchemy.models.child import Child
23
from examples.api_for_sqlalchemy.models.computer import Computer
4+
from examples.api_for_sqlalchemy.models.movie import Movie
35
from examples.api_for_sqlalchemy.models.parent import Parent
46
from examples.api_for_sqlalchemy.models.parent_to_child_association import ParentToChildAssociation
57
from examples.api_for_sqlalchemy.models.post import Post
@@ -9,8 +11,10 @@
911
from examples.api_for_sqlalchemy.models.workplace import Workplace
1012

1113
__all__ = (
14+
"AgeRating",
1215
"Child",
1316
"Computer",
17+
"Movie",
1418
"Parent",
1519
"ParentToChildAssociation",
1620
"Post",

tests/fixtures/models/age_rating.py renamed to examples/api_for_sqlalchemy/models/age_rating.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
from sqlalchemy import (
2-
String,
3-
Text,
4-
)
5-
from sqlalchemy.orm import Mapped, mapped_column
1+
from typing import TYPE_CHECKING
2+
3+
from sqlalchemy import String, Text
4+
from sqlalchemy.orm import Mapped, mapped_column, relationship
65

76
from examples.api_for_sqlalchemy.models.base import BaseMetadata
87

8+
if TYPE_CHECKING:
9+
from examples.api_for_sqlalchemy.models.movie import Movie
10+
911

1012
class AgeRating(BaseMetadata):
1113
__tablename__ = "age_rating"
@@ -20,5 +22,9 @@ class AgeRating(BaseMetadata):
2022
server_default="",
2123
)
2224

25+
movies: Mapped[list["Movie"]] = relationship(
26+
back_populates="age_rating_obj",
27+
)
28+
2329
def __str__(self) -> str:
2430
return self.name
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from typing import TYPE_CHECKING
2+
3+
from sqlalchemy import (
4+
ForeignKey,
5+
Identity,
6+
Integer,
7+
String,
8+
Text,
9+
)
10+
from sqlalchemy.orm import (
11+
Mapped,
12+
mapped_column,
13+
relationship,
14+
)
15+
16+
from examples.api_for_sqlalchemy.models.base import Base
17+
18+
if TYPE_CHECKING:
19+
from examples.api_for_sqlalchemy.models.age_rating import AgeRating
20+
21+
22+
class Movie(Base):
23+
__tablename__ = "movie"
24+
25+
id: Mapped[int] = mapped_column(
26+
Integer,
27+
Identity(always=True),
28+
primary_key=True,
29+
autoincrement=True,
30+
)
31+
title: Mapped[str] = mapped_column(
32+
String(120),
33+
index=True,
34+
)
35+
description: Mapped[str] = mapped_column(
36+
Text,
37+
default="",
38+
server_default="",
39+
)
40+
age_rating: Mapped[str | None] = mapped_column(
41+
ForeignKey(
42+
"age_rating.name",
43+
ondelete="SET NULL",
44+
),
45+
)
46+
age_rating_obj: Mapped["AgeRating"] = relationship(
47+
back_populates="movies",
48+
)
49+
50+
def __str__(self) -> str:
51+
return self.title
52+
53+
def __repr__(self) -> str:
54+
return f"Movie(id={self.id}, title={self.title!r})"

examples/api_for_sqlalchemy/schemas/__init__.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
from .age_rating import (
2+
AgeRatingAttributesSchema,
3+
AgeRatingBaseSchema,
4+
AgeRatingCreateSchema,
5+
AgeRatingSchema,
6+
AgeRatingUpdateSchema,
7+
)
18
from .child import (
29
ChildAttributesSchema,
310
ChildInSchema,
@@ -10,6 +17,13 @@
1017
ComputerPatchSchema,
1118
ComputerSchema,
1219
)
20+
from .movie import (
21+
MovieAttributesSchema,
22+
MovieBaseSchema,
23+
MovieCreateSchema,
24+
MovieSchema,
25+
MovieUpdateSchema,
26+
)
1327
from .parent import (
1428
ParentAttributesSchema,
1529
ParentInSchema,
@@ -51,6 +65,11 @@
5165
)
5266

5367
__all__ = (
68+
"AgeRatingAttributesSchema",
69+
"AgeRatingBaseSchema",
70+
"AgeRatingCreateSchema",
71+
"AgeRatingSchema",
72+
"AgeRatingUpdateSchema",
5473
"ChildAttributesSchema",
5574
"ChildInSchema",
5675
"ChildPatchSchema",
@@ -60,6 +79,11 @@
6079
"ComputerPatchSchema",
6180
"ComputerSchema",
6281
"CustomUserAttributesSchema",
82+
"MovieAttributesSchema",
83+
"MovieBaseSchema",
84+
"MovieCreateSchema",
85+
"MovieSchema",
86+
"MovieUpdateSchema",
6387
"ParentAttributesSchema",
6488
"ParentInSchema",
6589
"ParentPatchSchema",
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from typing import TYPE_CHECKING, Annotated, Optional
2+
3+
from annotated_types import MaxLen, MinLen
4+
from pydantic import ConfigDict
5+
6+
from fastapi_jsonapi.schema_base import BaseModel
7+
from fastapi_jsonapi.types_metadata import RelationshipInfo
8+
9+
name_constrained = Annotated[
10+
str,
11+
MinLen(1),
12+
MaxLen(20),
13+
]
14+
15+
if TYPE_CHECKING:
16+
from examples.api_for_sqlalchemy.schemas.movie import MovieSchema
17+
18+
19+
class AgeRatingAttributesSchema(BaseModel):
20+
model_config = ConfigDict(
21+
from_attributes=True,
22+
)
23+
name: str
24+
description: str
25+
26+
27+
class AgeRatingBaseSchema(AgeRatingAttributesSchema):
28+
movies: Annotated[
29+
Optional[list["MovieSchema"]],
30+
RelationshipInfo(
31+
resource_type="movie",
32+
many=True,
33+
),
34+
] = None
35+
36+
37+
class AgeRatingCreateSchema(AgeRatingBaseSchema):
38+
name: name_constrained
39+
40+
41+
class AgeRatingUpdateSchema(AgeRatingBaseSchema):
42+
name: Optional[name_constrained] = None
43+
description: Optional[str] = None
44+
45+
46+
class AgeRatingSchema(AgeRatingBaseSchema):
47+
"""
48+
Age Rating
49+
"""
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from datetime import date
2+
from typing import (
3+
TYPE_CHECKING,
4+
Annotated,
5+
Optional,
6+
)
7+
8+
from annotated_types import MaxLen, MinLen
9+
from pydantic import ConfigDict
10+
11+
from fastapi_jsonapi.schema_base import BaseModel
12+
from fastapi_jsonapi.types_metadata import RelationshipInfo
13+
14+
if TYPE_CHECKING:
15+
from examples.api_for_sqlalchemy.schemas.age_rating import AgeRatingSchema
16+
17+
title_constrained = Annotated[
18+
str,
19+
MinLen(1),
20+
MaxLen(120),
21+
]
22+
23+
24+
class MovieAttributesSchema(BaseModel):
25+
model_config = ConfigDict(
26+
from_attributes=True,
27+
)
28+
title: str
29+
description: str
30+
age_rating: str | None = None
31+
32+
33+
class MovieBaseSchema(MovieAttributesSchema):
34+
age_rating_obj: Annotated[
35+
Optional["AgeRatingSchema"],
36+
RelationshipInfo(
37+
resource_type="age-rating",
38+
resource_id_example="PG-13",
39+
id_field_name="name",
40+
),
41+
] = None
42+
43+
44+
class MovieCreateSchema(MovieBaseSchema):
45+
"""
46+
Create
47+
"""
48+
49+
title: title_constrained
50+
51+
52+
class MovieUpdateSchema(MovieBaseSchema):
53+
title: title_constrained | None = None
54+
description: str | None = None
55+
release_date: date | None = None
56+
duration: int | None = None
57+
58+
59+
class MovieSchema(MovieBaseSchema):
60+
id: int

examples/api_for_sqlalchemy/urls.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77

88
from .api.views_base import ViewBase
99
from .models import (
10+
AgeRating,
1011
Child,
1112
Computer,
13+
Movie,
1214
Parent,
1315
ParentToChildAssociation,
1416
Post,
@@ -17,12 +19,18 @@
1719
Workplace,
1820
)
1921
from .schemas import (
22+
AgeRatingCreateSchema,
23+
AgeRatingSchema,
24+
AgeRatingUpdateSchema,
2025
ChildInSchema,
2126
ChildPatchSchema,
2227
ChildSchema,
2328
ComputerInSchema,
2429
ComputerPatchSchema,
2530
ComputerSchema,
31+
MovieCreateSchema,
32+
MovieSchema,
33+
MovieUpdateSchema,
2634
ParentInSchema,
2735
ParentPatchSchema,
2836
ParentSchema,
@@ -131,6 +139,28 @@ def add_routes(app: FastAPI):
131139
schema_in_patch=WorkplacePatchSchema,
132140
schema_in_post=WorkplaceInSchema,
133141
)
142+
builder.add_resource(
143+
path="/age-ratings",
144+
tags=["Age Ratings"],
145+
resource_type="age-rating",
146+
view=ViewBase,
147+
model=AgeRating,
148+
schema=AgeRatingSchema,
149+
schema_in_post=AgeRatingCreateSchema,
150+
schema_in_patch=AgeRatingUpdateSchema,
151+
model_id_field_name="name",
152+
)
153+
builder.add_resource(
154+
path="/movies",
155+
tags=["Movie"],
156+
resource_type="movie",
157+
view=ViewBase,
158+
model=Movie,
159+
schema=MovieSchema,
160+
schema_in_post=MovieCreateSchema,
161+
schema_in_patch=MovieUpdateSchema,
162+
model_id_field_name="name",
163+
)
134164
builder.initialize()
135165

136166
atomic = AtomicOperations()

tests/fixtures/app.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
from pydantic import BaseModel, ConfigDict
77

88
from examples.api_for_sqlalchemy.models import (
9+
AgeRating,
910
Child,
1011
Computer,
12+
Movie,
1113
Parent,
1214
ParentToChildAssociation,
1315
Post,
@@ -16,12 +18,18 @@
1618
UserBio,
1719
)
1820
from examples.api_for_sqlalchemy.schemas import (
21+
AgeRatingCreateSchema,
22+
AgeRatingSchema,
23+
AgeRatingUpdateSchema,
1924
ChildInSchema,
2025
ChildPatchSchema,
2126
ChildSchema,
2227
ComputerInSchema,
2328
ComputerPatchSchema,
2429
ComputerSchema,
30+
MovieCreateSchema,
31+
MovieSchema,
32+
MovieUpdateSchema,
2533
ParentPatchSchema,
2634
ParentSchema,
2735
ParentToChildAssociationSchema,
@@ -39,11 +47,8 @@
3947
from fastapi_jsonapi.data_typing import TypeModel
4048
from fastapi_jsonapi.views.view_base import ViewBase
4149

42-
from .models import AgeRating, Alpha, Beta, CustomUUIDItem, Delta, Gamma, Task
50+
from .models import Alpha, Beta, CustomUUIDItem, Delta, Gamma, Task
4351
from .schemas import (
44-
AgeRatingCreateSchema,
45-
AgeRatingSchema,
46-
AgeRatingUpdateSchema,
4752
AlphaSchema,
4853
BetaSchema,
4954
CustomUUIDItemSchema,
@@ -176,6 +181,17 @@ def add_routers(app_plain: FastAPI):
176181
schema_in_patch=AgeRatingUpdateSchema,
177182
model_id_field_name="name",
178183
)
184+
builder.add_resource(
185+
path="/movies",
186+
tags=["Movie"],
187+
resource_type="movie",
188+
view=ViewBaseGeneric,
189+
model=Movie,
190+
schema=MovieSchema,
191+
schema_in_post=MovieCreateSchema,
192+
schema_in_patch=MovieUpdateSchema,
193+
model_id_field_name="name",
194+
)
179195
builder.initialize()
180196

181197
return app_plain

tests/fixtures/entities.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from sqlalchemy.ext.asyncio import AsyncSession
77

88
from examples.api_for_sqlalchemy.models import (
9+
AgeRating,
910
Child,
1011
Computer,
1112
Parent,
@@ -17,7 +18,7 @@
1718
Workplace,
1819
)
1920
from tests.common import is_postgres_tests
20-
from tests.fixtures.models import AgeRating, Task
21+
from tests.fixtures.models import Task
2122
from tests.misc.utils import fake
2223

2324

0 commit comments

Comments
 (0)