New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Paginate inner model field #361
Comments
@davidbrochart How JSON response should look like? smth like this? {
"other_data": 1000000,
"data_to_paginate": ["a", "b", "c"]
} |
Yes, exactly. |
@davidbrochart It looks ugly now( I will try to provide a better API for such purposes. from string import ascii_lowercase
from typing import Sequence, Type, TypeVar, Optional, Generic, cast
from fastapi import FastAPI
from fastapi_pagination.bases import AbstractPage, AbstractParams
from fastapi_pagination import add_pagination, paginate, Params
app = FastAPI()
T = TypeVar("T")
P = TypeVar("P", bound=AbstractPage)
class CustomResponse(AbstractPage[T], Generic[T]):
other_data: Optional[int] = None
data_to_paginate: Sequence[T]
__params_type__ = Params
@classmethod
def create(
cls: Type[P],
items: Sequence[T],
total: int,
params: AbstractParams,
) -> P:
return cls(data_to_paginate=items)
DATA = [*ascii_lowercase]
@app.get("/", response_model=CustomResponse[str])
def route():
response = cast(CustomResponse[str], paginate(DATA))
response.other_data = 42 # Add additional data to custom response
return response
add_pagination(app)
if __name__ == '__main__':
import uvicorn
uvicorn.run(app) |
@davidbrochart As for me ideal API should look like this: from string import ascii_lowercase
from typing import Sequence, Type, TypeVar, Optional, Generic, Dict, Any
from fastapi import FastAPI
from fastapi_pagination.bases import AbstractPage, AbstractParams
from fastapi_pagination import add_pagination, paginate, Params
app = FastAPI()
T = TypeVar("T")
P = TypeVar("P", bound=AbstractPage)
class CustomResponse(AbstractPage[T], Generic[T]):
other_data: Optional[int] = None
data_to_paginate: Sequence[T]
__params_type__ = Params
@classmethod
def create(
cls: Type[P],
items: Sequence[T],
total: int,
params: AbstractParams,
additional_data: Optional[Dict[str, Any]] = None,
) -> P:
return cls(
data_to_paginate=items,
**(additional_data or {}),
)
DATA = [*ascii_lowercase]
@app.get("/", response_model=CustomResponse[str])
def route():
return paginate(
DATA,
additional_data={
"other_data": 42,
},
)
add_pagination(app)
if __name__ == '__main__':
import uvicorn
uvicorn.run(app) So basically you can add additional fields that will be passed when the response model will be instantiated: return paginate(
DATA,
additional_data={
"other_data": 42,
},
) What do you think about such API? Maybe you have other ideas? |
My original class ResponseType(BaseModel):
other_data: int
data_to_paginate: Sequence[str] But actually my real use-case is more complex. Ideally this model could be as big as we want, and the data to paginate could even be nested deep inside, so we don't want to add back all the other data around the data to paginate "by hand". |
I think yes. Could you please show how API should look like in your opinion? |
I'm not sure, maybe something like this: class CustomResponse(AbstractPage[T], Generic[T]):
__root__: ResponseType
__params_type__ = Params
@classmethod
def create(
cls: Type[P],
items: Sequence[T],
total: int,
params: AbstractParams,
) -> P:
data = get_response()
data.data_to_paginate = items
return cls(__root__=data) But I'm probably missing something. |
Thanks for your suggestion. I will try to think about a good API for such feature. Currently, as a workaround you can access paginated items and pass them to your custom schema: from string import ascii_lowercase
from typing import Sequence, cast
from fastapi import FastAPI, Depends
from pydantic import BaseModel
from fastapi_pagination import add_pagination, paginate, Params, Page
app = FastAPI()
class ResponseType(BaseModel):
other_data: int
data_to_paginate: Sequence[str]
DATA = [*ascii_lowercase]
@app.get("/", response_model=ResponseType)
def route(params: Params = Depends()):
data_to_paginate = cast(Page[str], paginate(DATA, params)).items
return ResponseType(
other_data=42,
data_to_paginate=data_to_paginate,
)
add_pagination(app)
if __name__ == '__main__':
import uvicorn
uvicorn.run(app) |
Thanks, but I'm not sure I understand. This doesn't return a |
Hi @davidbrochart, Now it should be easier to implement this feature. Example: from typing import Any, TypeVar, Generic, Sequence, Type
from fastapi import FastAPI
from pydantic import BaseModel, Field
from fastapi_pagination import paginate, Params
from fastapi_pagination.api import pagination_items, add_pagination
from fastapi_pagination.bases import AbstractPage, AbstractParams
app = FastAPI()
add_pagination(app)
T = TypeVar("T")
C = TypeVar("C")
class PageWithInnerItems(AbstractPage[T], Generic[T]):
__root__: T
__params_type__ = Params
@classmethod
def create(
cls: Type[C],
items: Sequence[T],
params: AbstractParams,
**kwargs: Any,
) -> C:
return cls(__root__=kwargs)
class ResponseType(BaseModel):
other_data: int
data_to_paginate: Sequence[str] = Field(default_factory=pagination_items)
@app.get(
"/",
response_model=PageWithInnerItems[ResponseType],
)
async def route() -> Any:
data = [*range(100)]
return paginate(data, additional_data={"other_data": 1000000})
if __name__ == '__main__':
import uvicorn
uvicorn.run(app) |
Hi @davidbrochart, |
Thanks a lot for the work, I had to switch to something else but I will probably need these new features in the future. |
Great library, thanks!
How would you go about using it on an endpoint which doesn't directly return a sequence, but a model in which a field is the sequence to paginate, e.g.:
The text was updated successfully, but these errors were encountered: