Skip to content

Commit 0311258

Browse files
committed
feat: add Lookups documentation and implement flexible lookup system for FastAPI Mason. Rename methods in pagination and schemas
1 parent 152d93c commit 0311258

22 files changed

Lines changed: 451 additions & 238 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ from tortoise.models import Model
5858

5959
from fastapi_mason.decorators import action, viewset
6060
from fastapi_mason.pagination import PageNumberPagination
61-
from fastapi_mason.schemas import SchemaMeta, generate_schema, rebuild_schema
61+
from fastapi_mason.schemas import SchemaMeta, build_schema, rebuild_schema
6262
from fastapi_mason.viewsets import ModelViewSet
6363
from fastapi_mason.wrappers import PaginatedResponseDataWrapper, ResponseDataWrapper
6464

@@ -85,7 +85,7 @@ class CompanyMeta(SchemaMeta):
8585
include = ('id', 'name', 'full_name', 'created_at', 'updated_at')
8686

8787
# Schemas
88-
CompanySchema = generate_schema(Company, meta=CompanyMeta)
88+
CompanySchema = build_schema(Company, meta=CompanyMeta)
8989
CompanyCreateSchema = rebuild_schema(CompanySchema, exclude_readonly=True)
9090

9191
# Views

app/domains/company/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@
66
class Company(BaseModel):
77
name = fields.CharField(max_length=255)
88
full_name = fields.TextField(null=True)
9+
10+
class Meta:
11+
ordering = ['-id']

app/domains/company/schemas.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from app.domains.company.meta import CompanyMeta
22
from app.domains.company.models import Company
3-
from fastapi_mason.schemas import generate_schema, rebuild_schema
3+
from fastapi_mason.schemas import build_schema, rebuild_schema
44

5-
CompanySchema = generate_schema(Company, meta=CompanyMeta)
5+
CompanySchema = build_schema(Company, meta=CompanyMeta)
66
CompanyCreateSchema = rebuild_schema(CompanySchema, exclude_readonly=True)

app/domains/project/meta.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from app.core.models import BASE_FIELDS
22
from app.domains.company.meta import CompanyMeta
3-
from fastapi_mason.schemas import SchemaMeta, generate_schema_meta
3+
from fastapi_mason.schemas import SchemaMeta, build_schema_meta
44

55

66
class ProjectMeta(SchemaMeta):
@@ -21,12 +21,12 @@ class TaskMeta(SchemaMeta):
2121

2222

2323
def get_project_with_tasks_meta():
24-
return generate_schema_meta(
24+
return build_schema_meta(
2525
ProjectMeta,
2626
('company', CompanyMeta),
2727
('tasks', get_task_with_project_meta()),
2828
)
2929

3030

3131
def get_task_with_project_meta():
32-
return generate_schema_meta(TaskMeta, ('project', ProjectMeta))
32+
return build_schema_meta(TaskMeta, ('project', ProjectMeta))

app/domains/project/schemas.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
from app.domains.project.meta import get_project_with_tasks_meta, get_task_with_project_meta
66
from app.domains.project.models import Project, Task
7-
from fastapi_mason.schemas import ConfigSchemaMeta, generate_schema, rebuild_schema
7+
from fastapi_mason.schemas import ConfigSchemaMeta, build_schema, rebuild_schema
88

9-
ProjectReadSchema = generate_schema(
9+
ProjectReadSchema = build_schema(
1010
Project,
1111
meta=get_project_with_tasks_meta(),
1212
config=ConfigSchemaMeta(allow_cycles=True),
@@ -18,7 +18,7 @@
1818
)
1919

2020

21-
TaskReadSchema = generate_schema(Task, meta=get_task_with_project_meta())
21+
TaskReadSchema = build_schema(Task, meta=get_task_with_project_meta())
2222
TaskCreateSchema = rebuild_schema(TaskReadSchema, exclude_readonly=True)
2323

2424

docs/assets/metrics.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ ym(103332320, "init", {
99
trackLinks:true,
1010
accurateTrackBounce:true,
1111
webvisor:true
12-
});
12+
});

docs/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ from tortoise.models import Model
5656

5757
from fastapi_mason.decorators import action, viewset
5858
from fastapi_mason.pagination import PageNumberPagination
59-
from fastapi_mason.schemas import SchemaMeta, generate_schema, rebuild_schema
59+
from fastapi_mason.schemas import SchemaMeta, build_schema, rebuild_schema
6060
from fastapi_mason.viewsets import ModelViewSet
6161
from fastapi_mason.wrappers import PaginatedResponseDataWrapper, ResponseDataWrapper
6262

@@ -87,7 +87,7 @@ class CompanyMeta(SchemaMeta):
8787

8888

8989
# Schemas
90-
CompanySchema = generate_schema(Company, meta=CompanyMeta)
90+
CompanySchema = build_schema(Company, meta=CompanyMeta)
9191
CompanyCreateSchema = rebuild_schema(CompanySchema, exclude_readonly=True)
9292

9393
# Views

docs/pagination.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,12 @@ class CompanyViewSet(ModelViewSet[Company]):
157157
pagination = PageNumberPagination
158158

159159
@action(methods=["GET"], response_model=List[ProjectReadSchema])
160-
async def paginated_list(self, pagination: PageNumberPagination = Depends(PageNumberPagination.from_query)):
160+
async def paginated_list(self, pagination: PageNumberPagination = Depends(PageNumberPagination.build)):
161161
queryset = self.get_queryset()
162162
return await self.get_paginated_response(queryset=queryset, pagination=pagination)
163163

164164
@action(methods=["GET"], response_model=PaginatedResponseDataWrapper[ProjectReadSchema, PageNumberPagination[Company]])
165-
async def wrapped_paginated_list(self, pagination: PageNumberPagination = Depends(PageNumberPagination.from_query)):
165+
async def wrapped_paginated_list(self, pagination: PageNumberPagination = Depends(PageNumberPagination.build)):
166166
queryset = self.get_queryset()
167167
return await self.get_paginated_response(queryset=queryset, pagination=pagination, wrapper=PaginatedResponseDataWrapper)
168168
```
@@ -182,7 +182,7 @@ class CustomPageNumberPagination(PageNumberPagination[ModelType]):
182182
"""Custom pagination implementation with flexible page size and offset."""
183183

184184
@classmethod
185-
def from_query(
185+
def build(
186186
cls,
187187
page: int = Query(1, ge=1, description="Page number"),
188188
size: int = Query(20, ge=1, le=1000, description="Number of records per page"),
@@ -210,7 +210,7 @@ class CustomPagination(Pagination[ModelType]):
210210
pages: int = 0
211211

212212
@classmethod
213-
def from_query(
213+
def build(
214214
cls,
215215
page: int = Query(1, ge=1, description="Page number to retrieve"),
216216
size: int = Query(10, ge=1, le=50, description="Number of records per page"),
@@ -231,6 +231,6 @@ class CustomPagination(Pagination[ModelType]):
231231

232232
**Explanation**
233233

234-
- `from_query`: Defines how query parameters are parsed into the pagination instance. In this example, it uses page and size with constraints (e.g., size capped at 50).
234+
- `build`: Defines how query parameters are parsed into the pagination instance. In this example, it uses page and size with constraints (e.g., size capped at 50).
235235
- `paginate`: Applies the pagination logic to the queryset, calculating the offset based on the page and size, then limiting the results.
236236
- `fill_meta`: Computes metadata like the total item count and number of pages, ensuring accurate pagination information in the response.

docs/quick-start.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ Define which fields to include in your API schemas and how to handle relationshi
111111

112112
```python title="app/domains/project/meta.py"
113113
from app.core.models import BASE_FIELDS
114-
from fastapi_mason.schemas import SchemaMeta, generate_schema_meta
114+
from fastapi_mason.schemas import SchemaMeta, build_schema_meta
115115

116116

117117
class ProjectMeta(SchemaMeta):
@@ -135,15 +135,15 @@ class TaskMeta(SchemaMeta):
135135
# Create meta for nested schemas with relationships
136136
def get_project_with_tasks_meta():
137137
"""Project schema with embedded tasks"""
138-
return generate_schema_meta(
138+
return build_schema_meta(
139139
ProjectMeta,
140140
("tasks", get_task_with_project_meta()),
141141
)
142142

143143

144144
def get_task_with_project_meta():
145145
"""Task schema with embedded project data"""
146-
return generate_schema_meta(TaskMeta, ("project", ProjectMeta))
146+
return build_schema_meta(TaskMeta, ("project", ProjectMeta))
147147
```
148148

149149
### 5. Generate Schemas
@@ -162,7 +162,7 @@ from app.domains.project.meta import (
162162
get_task_with_project_meta,
163163
)
164164
from app.domains.project.models import Project, Task
165-
from fastapi_mason.schemas import ConfigSchemaMeta, generate_schema, rebuild_schema
165+
from fastapi_mason.schemas import ConfigSchemaMeta, build_schema, rebuild_schema
166166

167167
"""
168168
https://tortoise.github.io/examples/pydantic.html?h=init_models#early-model-init
@@ -172,10 +172,10 @@ https://github.com/bubaley/fastapi-mason/blob/main/app/core/database.py
172172
Tortoise.init_models(["app.domains.project.models"], "models")
173173

174174
# Simple project schema
175-
ProjectReadSchema = generate_schema(Project, meta=ProjectMeta)
175+
ProjectReadSchema = build_schema(Project, meta=ProjectMeta)
176176

177177
# Detailed project schema with tasks (handles circular references)
178-
ProjectDetailSchema = generate_schema(
178+
ProjectDetailSchema = build_schema(
179179
Project,
180180
meta=get_project_with_tasks_meta(),
181181
config=ConfigSchemaMeta(allow_cycles=True), # Handle circular references
@@ -192,7 +192,7 @@ class ProjectStatsSchema(BaseModel):
192192

193193

194194
# Task schemas
195-
TaskReadSchema = generate_schema(Task, meta=get_task_with_project_meta())
195+
TaskReadSchema = build_schema(Task, meta=get_task_with_project_meta())
196196
TaskCreateSchema = rebuild_schema(TaskReadSchema, exclude_readonly=True)
197197

198198
# Type checking support
@@ -267,7 +267,7 @@ class TaskViewSet(BaseViewSet[Task]):
267267
@action(methods=["GET"], response_model=PaginatedResponseDataWrapper[TaskReadSchema, PageNumberPagination])
268268
async def list(
269269
self,
270-
pagination: PageNumberPagination = Depends(PageNumberPagination.from_query),
270+
pagination: PageNumberPagination = Depends(PageNumberPagination.build),
271271
project_id: bool = Query(...),
272272
):
273273
"""Override list method"""
@@ -393,14 +393,14 @@ And tasks endpoints.
393393

394394
### 1. **Relationship Handling**
395395

396-
- ForeignKey and related objects are automatically included in schemas using `generate_schema_meta`.
396+
- ForeignKey and related objects are automatically included in schemas using `build_schema_meta`.
397397
- Nested object serialization (e.g., project with tasks, task with project).
398398
- Circular reference support with `ConfigSchemaMeta(allow_cycles=True)`.
399399

400400
### 2. **Flexible Schema Generation**
401401

402402
- Different schemas for list and detail views.
403-
- Customizable field inclusion through meta classes (`SchemaMeta`, `generate_schema_meta`).
403+
- Customizable field inclusion through meta classes (`SchemaMeta`, `build_schema_meta`).
404404
- Generation of nested schemas for related models.
405405

406406
### 3. **Base and Custom ViewSets**

docs/schemas.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The `config` parameter uses `PydanticMetaData`, allowing you to apply all standa
1111
The schema system consists of three main components:
1212

1313
1. **SchemaMeta** - Defines which fields to include/exclude
14-
2. **generate_schema()** - Creates Pydantic models from Tortoise models
14+
2. **build_schema()** - Creates Pydantic models from Tortoise models
1515
3. **rebuild_schema()** - Modifies existing schemas for different use cases
1616

1717
## SchemaMeta Classes
@@ -73,12 +73,12 @@ class ProjectMeta(SchemaMeta):
7373
```
7474

7575
```python title="app/domains/project/schemas.py"
76-
from fastapi_mason.schemas import generate_schema, rebuild_schema
76+
from fastapi_mason.schemas import build_schema, rebuild_schema
7777
from app.domains.project.models import Project
7878
from app.domains.project.meta import ProjectMeta
7979

8080
# Generate read schema (includes all fields)
81-
ProjectReadSchema = generate_schema(Project, meta=ProjectMeta)
81+
ProjectReadSchema = build_schema(Project, meta=ProjectMeta)
8282

8383
# Generate create schema (excludes readonly fields)
8484
ProjectCreateSchema = rebuild_schema(
@@ -105,7 +105,7 @@ class Task(BaseModel):
105105
### Meta Classes for Relationships
106106

107107
```python title="app/domains/project/meta.py"
108-
from fastapi_mason.schemas import SchemaMeta, generate_schema_meta
108+
from fastapi_mason.schemas import SchemaMeta, build_schema_meta
109109

110110
class ProjectMeta(SchemaMeta):
111111
include = (
@@ -125,27 +125,27 @@ class TaskMeta(SchemaMeta):
125125
# Create meta for nested schemas with relationships
126126
def get_project_with_tasks_meta():
127127
"""Project schema with embedded tasks"""
128-
return generate_schema_meta(
128+
return build_schema_meta(
129129
ProjectMeta,
130130
('tasks', get_task_with_project_meta()),
131131
)
132132

133133
def get_task_with_project_meta():
134134
"""Task schema with embedded project data"""
135-
return generate_schema_meta(TaskMeta, ('project', ProjectMeta))
135+
return build_schema_meta(TaskMeta, ('project', ProjectMeta))
136136
```
137137

138138
### Schema Generation with Relationships
139139

140140
```python title="app/domains/project/schemas.py"
141-
from fastapi_mason.schemas import ConfigSchemaMeta, generate_schema, rebuild_schema
141+
from fastapi_mason.schemas import ConfigSchemaMeta, build_schema, rebuild_schema
142142

143143
# Simple schemas
144-
ProjectReadSchema = generate_schema(Project, meta=ProjectMeta)
145-
TaskReadSchema = generate_schema(Task, meta=get_task_with_project_meta())
144+
ProjectReadSchema = build_schema(Project, meta=ProjectMeta)
145+
TaskReadSchema = build_schema(Task, meta=get_task_with_project_meta())
146146

147147
# Detailed project schema with tasks (handles circular references)
148-
ProjectDetailSchema = generate_schema(
148+
ProjectDetailSchema = build_schema(
149149
Project,
150150
meta=get_project_with_tasks_meta(),
151151
config=ConfigSchemaMeta(allow_cycles=True), # Handle circular references
@@ -162,7 +162,7 @@ The `rebuild_schema()` function allows you to create variations of existing sche
162162

163163
```python
164164
# Original schema includes all fields
165-
ProjectReadSchema = generate_schema(Project, meta=ProjectMeta)
165+
ProjectReadSchema = build_schema(Project, meta=ProjectMeta)
166166

167167
# Create schema excludes readonly fields like id, created_at, updated_at
168168
ProjectCreateSchema = rebuild_schema(
@@ -197,7 +197,7 @@ config = ConfigSchemaMeta(
197197
include=('custom_field',),
198198
)
199199

200-
schema = generate_schema(
200+
schema = build_schema(
201201
Project,
202202
meta=ProjectMeta,
203203
config=config
@@ -213,7 +213,7 @@ from typing import TYPE_CHECKING
213213
from tortoise.contrib.pydantic import PydanticModel
214214

215215
# Runtime schema generation
216-
ProjectSchema = generate_schema(Project, meta=ProjectMeta)
216+
ProjectSchema = build_schema(Project, meta=ProjectMeta)
217217

218218
# Type hints for IDE
219219
if TYPE_CHECKING:
@@ -268,8 +268,8 @@ class ProjectMetas:
268268
include = ('name', 'description')
269269

270270
# Use specific meta for different contexts
271-
ProjectListSchema = generate_schema(Project, meta=ProjectMetas.List)
272-
ProjectDetailSchema = generate_schema(Project, meta=ProjectMetas.Detail)
271+
ProjectListSchema = build_schema(Project, meta=ProjectMetas.List)
272+
ProjectDetailSchema = build_schema(Project, meta=ProjectMetas.Detail)
273273
```
274274

275275
## Common Patterns
@@ -278,16 +278,16 @@ ProjectDetailSchema = generate_schema(Project, meta=ProjectMetas.Detail)
278278

279279
```python
280280
# Different schemas for different API responses
281-
ProjectListSchema = generate_schema(Project, meta=ProjectListMeta) # Minimal fields
282-
ProjectDetailSchema = generate_schema(Project, meta=ProjectDetailMeta) # Full fields
281+
ProjectListSchema = build_schema(Project, meta=ProjectListMeta) # Minimal fields
282+
ProjectDetailSchema = build_schema(Project, meta=ProjectDetailMeta) # Full fields
283283
ProjectCreateSchema = rebuild_schema(ProjectDetailSchema, exclude_readonly=True)
284284
```
285285

286286
### Schema Naming
287287

288288
```python
289289
# Explicit naming for better OpenAPI documentation
290-
ProjectReadSchema = generate_schema(
290+
ProjectReadSchema = build_schema(
291291
Project,
292292
meta=ProjectMeta,
293293
name="ProjectResponse"

0 commit comments

Comments
 (0)