Coder Social home page Coder Social logo

uriyyo / fastapi-pagination Goto Github PK

View Code? Open in Web Editor NEW
1.0K 10.0 120.0 4.47 MB

FastAPI pagination ๐Ÿ“–

Home Page: https://uriyyo-fastapi-pagination.netlify.app/

License: MIT License

Python 100.00%
fastapi fastapi-sqlalchemy fastapi-pagination pagination gino

fastapi-pagination's Introduction

Hi there ๐Ÿ‘‹

Can you help me learn Haskell?

My OOP mind struggles every time I attempt to learn it ๐Ÿ˜ข

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

About me

I am a Software Engineer who mostly works with Python but used to work with C/C++ and Java a long time ago. Hope one day I will be able to understand Haskell (I have a dream to learn functional programming).

PEP 505 None-aware operators is a feature that I miss the most in Python.

I?.really?.want?.this?.feature ?? "Or not?"

Things done by me

FastAPI related

If you are using FastAPI and use function return type annotation as response_model you should know - I am the one who implemented it ๐Ÿ˜„ (FastAPI #1436).

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI(title="Bio")


class Bio(BaseModel):
    name: str
    education: str
    languages: set[str]


@app.get("/me")
async def get_bio() -> Bio:
    return Bio(
        name="Yurii",
        education="Master's degree in Computer Engineering",
        languages={"Ukrainian", "English", "Polish", "German (a bit)"},
    )

Also, I have created fastapi-pagination package that helps you to paginate things (obviously) using FastAPI ๐Ÿ“–. Another thing that I currently work on is fastapi-filters package. Hope one day it will be useful for someone as fastapi-pagination is ๐Ÿธ.

Python related

I have several contributions to Python itself (commits). The most interesting one is (#23316 Store func annotations as a tuple). This optimization reduces memory footprint and improves performance of loading modules having many func annotations.

>>> sys.getsizeof({"a":"int","b":"int","return":"int"})
232
>>> sys.getsizeof(("a","int","b","int","return","int"))
88

The tuple is converted into dict on the fly when func.__annotations__ is accessed first.

PyCharm related

I have created a plugin (pycharm-evaluate-async-code) for PyCharm that helps you evaluate async code the using Evaluate Expression window. This is really useful when you are debugging your code and want to check some async stuff. I guess it's my favorite project that I have ever done (because I used it every day and it really saved me a lot of time).

evaluate_expression

fastapi-pagination's People

Contributors

07pepa avatar arthurio avatar barsikus007 avatar benhaimitay avatar collerek avatar dependabot-preview[bot] avatar dependabot[bot] avatar devalv avatar dudzicz avatar github-actions[bot] avatar harry-lees avatar ihnokim avatar johnthagen avatar jonra1993 avatar karichevi avatar kigawas avatar lingster avatar markbaas avatar michaelbukachi avatar morian avatar nikstuckenbrock avatar pipeknight avatar rushilsrivastava avatar s-rigaud avatar siddharth21s avatar tjc15b avatar tworedz avatar uriyyo avatar xeryustc avatar zsltg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fastapi-pagination's Issues

can't run sqlalchmey example.

I'm attempting to run this example: https://github.com/uriyyo/fastapi-pagination/blob/main/examples/pagination_sqlalchemy.py

It tells me:

ERROR:    Error loading ASGI app. Could not import module "pagination_sqlalchemy".

I've tried pip install pagination_sqlalchemy, but that tells me:

ERROR: Could not find a version that satisfies the requirement pagination_sqlalchemy (from versions: none)
ERROR: No matching distribution found for pagination_sqlalchemy

I previously ran pip install fastapi-pagination[all] to pull in this library.

SQLAlchemy pagination error - pydantic.error_wrappers.ValidationError

Hi! ๐Ÿ‘‹

version 0.7.1

For sqlalchemy extension in function fastapi_pagination.ext.sqlalchemy.paginate, we should rather return list of dicts instead of tuples:
https://github.com/uriyyo/fastapi-pagination/blob/0.7.1/fastapi_pagination/ext/sqlalchemy.py#L23

I get the validation error there
items = paginate_query(query, params).all() # as is
items = [item._asdict() for item in paginate_query(query, params)] # proposal

Thanks ๐Ÿ™Œ

Fastapi-pagination Throwing error on linux instance.

I am working on a project where pagination is working fine but as i take a step forward to host it on AWS EC2 ubuntu instance, it started throwing error like

ERROR: Could not find a version that satisfies the requirement fastapi-pagination==0.5.1
ERROR: No matching distribution found for fastapi-pagination==0.5.1

It also worked fine on heroku,
i am not able to understand that this problem is from AWS or package.

custom parameter to replace "total" field on Page

I'm trying to replace the "total" field in fastapi-pagination because I'm querying a dynamodb database that has query limitations.

The database is limited to showing more than 1000 rows. To be able to see all the results without querying I have to create a function that counts all the rows in the table and pass it to the "total" field.

Is this possible and if yes, how?

Any help appreciated.

How to pass a custom size in pagination_params

Hi,
Can you please let me know if there is any way that we can pass a custom size=xx in pagination params.

As of now by default it passes 50 as per page size.
Where can I pass a custom size in the below code?

@router.get("/", response_model=Page[schemas.Table1B], dependencies=[Depends(pagination_params)])
def get_table(db: Session = Depends(get_db)) -> Any:
    return paginate(db.query(models.Table1).all())

Thanks.

ormar example raises AttributeError when queried

I tried running the ormar example as is and it did not work:

# OS: macOS

(venv) $ python --version
Python 3.9.1

(venv) $ pip freeze
aiosqlite==0.17.0
click==7.1.2
databases==0.4.1
Faker==8.1.0
fastapi==0.63.0
fastapi-pagination==0.7.0
h11==0.12.0
ormar==0.10.4
pydantic==1.8
python-dateutil==2.8.1
six==1.15.0
SQLAlchemy==1.3.23
starlette==0.13.6
text-unidecode==1.3
typing-extensions==3.7.4.3
uvicorn==0.13.4

(venv) $ uvicorn pagination_ormar:app --reload
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [60370] using statreload
INFO:     Started server process [60372]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     127.0.0.1:58059 - "GET /docs HTTP/1.1" 200 OK
INFO:     127.0.0.1:58059 - "GET /openapi.json HTTP/1.1" 200 OK
INFO:     127.0.0.1:58059 - "GET /docs HTTP/1.1" 200 OK
INFO:     127.0.0.1:58059 - "GET /openapi.json HTTP/1.1" 200 OK
INFO:     127.0.0.1:58059 - "GET /users/limit-offset?limit=50&offset=0 HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "./venv/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py", line 396, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "./venv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "./venv/lib/python3.9/site-packages/fastapi/applications.py", line 199, in __call__
    await super().__call__(scope, receive, send)
  File "./venv/lib/python3.9/site-packages/starlette/applications.py", line 111, in __call__
    await self.middleware_stack(scope, receive, send)
  File "./venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "./venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "./venv/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "./venv/lib/python3.9/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "./venv/lib/python3.9/site-packages/starlette/routing.py", line 566, in __call__
    await route.handle(scope, receive, send)
  File "./venv/lib/python3.9/site-packages/starlette/routing.py", line 227, in handle
    await self.app(scope, receive, send)
  File "./venv/lib/python3.9/site-packages/starlette/routing.py", line 41, in app
    response = await func(request)
  File "./venv/lib/python3.9/site-packages/fastapi/routing.py", line 209, in app
    response_data = await serialize_response(
  File "./venv/lib/python3.9/site-packages/fastapi/routing.py", line 109, in serialize_response
    response_content = _prepare_response_content(
  File "./venv/lib/python3.9/site-packages/fastapi/routing.py", line 66, in _prepare_response_content
    return res.dict(
  File "pydantic/main.py", line 495, in pydantic.main.BaseModel.dict
  File "pydantic/main.py", line 859, in _iter
  File "pydantic/main.py", line 800, in pydantic.main.BaseModel._get_value
  File "pydantic/main.py", line 785, in genexpr
  File "pydantic/main.py", line 749, in pydantic.main.BaseModel._get_value
  File "./venv/lib/python3.9/site-packages/ormar/models/newbasemodel.py", line 700, in dict
    pk_only = object.__getattribute__(self, "__pk_only__")
AttributeError: __pk_only__
INFO:     127.0.0.1:58066 - "GET /users/default?page=0&size=50 HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "./venv/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py", line 396, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "./venv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "./venv/lib/python3.9/site-packages/fastapi/applications.py", line 199, in __call__
    await super().__call__(scope, receive, send)
  File "./venv/lib/python3.9/site-packages/starlette/applications.py", line 111, in __call__
    await self.middleware_stack(scope, receive, send)
  File "./venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "./venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "./venv/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "./venv/lib/python3.9/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "./venv/lib/python3.9/site-packages/starlette/routing.py", line 566, in __call__
    await route.handle(scope, receive, send)
  File "./venv/lib/python3.9/site-packages/starlette/routing.py", line 227, in handle
    await self.app(scope, receive, send)
  File "./venv/lib/python3.9/site-packages/starlette/routing.py", line 41, in app
    response = await func(request)
  File "./venv/lib/python3.9/site-packages/fastapi/routing.py", line 209, in app
    response_data = await serialize_response(
  File "./venv/lib/python3.9/site-packages/fastapi/routing.py", line 109, in serialize_response
    response_content = _prepare_response_content(
  File "./venv/lib/python3.9/site-packages/fastapi/routing.py", line 66, in _prepare_response_content
    return res.dict(
  File "pydantic/main.py", line 495, in pydantic.main.BaseModel.dict
  File "pydantic/main.py", line 859, in _iter
  File "pydantic/main.py", line 800, in pydantic.main.BaseModel._get_value
  File "pydantic/main.py", line 785, in genexpr
  File "pydantic/main.py", line 749, in pydantic.main.BaseModel._get_value
  File "./venv/lib/python3.9/site-packages/ormar/models/newbasemodel.py", line 700, in dict
    pk_only = object.__getattribute__(self, "__pk_only__")
AttributeError: __pk_only__

CC @collerek

How do you get the next page?

Hey Yurii.

How do you get the next page?

I inserted 100 users into the database but I can only see the first page but cannot go to the next.

Thanks

Async pagination not working with joined eager loads

Hi,

I'm trying to use the async pagination but it doesn't seem to work with models that have joined eager loads against collections. Take a look at the following minimal example:

import asyncio

from fastapi_pagination.bases import RawParams, AbstractParams
from fastapi_pagination.ext.sqlalchemy import paginate_query
from pydantic import BaseModel, conint
from sqlalchemy import Integer, Column, String, Text, ForeignKey, func
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.future import select
from sqlalchemy.orm import declarative_base, relationship, sessionmaker, joinedload

Base = declarative_base()


class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    articles = relationship('Article')


class Article(Base):
    __tablename__ = 'articles'

    id = Column(Integer, primary_key=True)
    title = Column(String)
    content = Column(Text)
    user_id = Column(ForeignKey('users.id'))


class PaginationQueryParams(BaseModel, AbstractParams):
    page: conint(ge=1) = 1  # type: ignore
    per_page: int = 100

    def to_raw_params(self) -> RawParams:
        return RawParams(limit=self.per_page, offset=(self.page - 1) * self.per_page)


async def main():
    engine = create_async_engine('sqlite+aiosqlite:///sample.sqlite')

    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.drop_all)
        await conn.run_sync(Base.metadata.create_all)

    async_session = sessionmaker(
        engine, expire_on_commit=False, class_=AsyncSession
    )
    async with async_session() as session:
        async with session.begin():
            session.add(User(name='test', articles=[Article(title='test', content='test')]))
        await session.commit()
        stmt = select(User).options(joinedload(User.articles))
        total = await session.scalar(select(func.count()).select_from(stmt.subquery()))  # type: ignore
        params = PaginationQueryParams()
        items = await session.execute(paginate_query(stmt, params))
        print([*items.scalars()])


if __name__ == '__main__':
    asyncio.run(main())

if you replace this line (remove eager load options)

        stmt = select(User).options(joinedload(User.articles))

with

        stmt = select(User)

it works.
Based on this issue and this commit, the proposed solution is to add the unique() call like so:

print([*items.scalars().unique()])

I've tested it with the above snippet and it's working. Willing to do a PR for this.

Alias for `items` key - Tortoise ORM

Hello,
I have the following code, which works fine:

from fastapi_pagination.links import Page
from fastapi_pagination.ext.tortoise import paginate

@router.get("/test_endpoint", response_model=Page[MyModel])
async def get_api_keys(params: Params = Depends(Params)):
    data = MyModel.filter().all()

    return await paginate(data, params=params)

But, when I am trying to show output with key data, instead of items, like it was in documentation, getting the error:

class JsonApiPage(Page[T], Generic[T]):
    """JSON:API 1.0 specification says that result key should be a `data`."""

    class Config:
        fields = {"items": {"alias": "data"}}
        
@router.get("/test_endpoint", response_model=JsonApiPage[MyModel])
async def get_api_keys(params: Params = Depends(Params)):
    data = MyModel.filter().all()

    return await paginate(data, params=params)

output:

     			return await paginate(data, params=params)
         |   File "/usr/local/lib/python3.8/site-packages/fastapi_pagination/ext/tortoise.py", line 21, in paginate
         |     return create_page(items, total, params)
         |   File "/usr/local/lib/python3.8/site-packages/fastapi_pagination/api.py", line 50, in create_page
         |     return page_type.get().create(items, total, params)
         |   File "/usr/local/lib/python3.8/site-packages/fastapi_pagination/default.py", line 47, in create
         |     return cls(
         |   File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
         | pydantic.error_wrappers.ValidationError: 1 validation error for JsonApiPage[ApiKeyOut]
         | data
         |   field required (type=value_error.missing)

Any ideas how to make alias for items key?

Unalbe to import pagination_params

Earlier when I have installed fastapi-pagination it was 0.5.2 it was working fine

Today I installed then the version is .0.6.1

now it produces following error.

from fastapi_pagination import pagination_params
ImportError: cannot import name 'pagination_params' from 'fastapi_pagination'

when I am trying to import :

from fastapi_pagination import pagination_params
from fastapi_pagination.paginator import paginate
from fastapi_pagination import PaginationParams, Page

Same code is working fine in 0.5.2

Any help is appreciated.

[enh] Use islice rather than slice in order to work with generators.

Right now, you select the data using []. itertools.islice stills works on sequences, but also works on generators, which is useful when there is a lot of data to go through.

Specifically, I think replacing this line:

items=sequence[raw_params.offset : raw_params.offset + raw_params.limit],
would be sufficient to add the functionality while changing nothing in the existing API.

The line would become

items=list(it.islice(sequence, raw_params.offset, raw_params.offset + raw_params.limit]),

(after import itertools as it).

What do you think?

[Question] Any plan for integration with piccolo

Hi @uriyyo thanks for all the hardwork that has been put into this project. Would you plan on an integration with piccolo-orm (https://piccolo-orm.com/) in the coming days. We use piccolo for simplicity in its migrations and usage like django but with async capabilities.
If you get sometime to look over piccolo please do suggest any ideas you'd get on paginating a piccolo queryset with fast api.

Problem with sqlalchemy .

async def search_offertypes(order: bool = False, parameter: OffertypeList = Depends(),
db: Session = Depends(get_db)) -> Any:
return paginate(db.query(OfferType))

output:

TypeError: object of type 'Query' has no len()

Add support for Django orm

Hi,
I was wondering if you can review the PR: #59

This adds a new extension to be used with Django. One problem was how to map from a django model to a pydantic model, so I updated paginate() to access a BaseModel which expects a from_django() method to convert from django to a pydantic model.

I was also considering djantic as a possible solution.
Open to your thoughts for improvements!
Thanks,
Ling

Increasing limit value

Hey there, is it possible to increase the limit value? I tried to define pagination_params as below (informed by #17), but had no luck. What is the correct way to do it?

Thanks!

from fastapi_pagination import Page, using_params
from fastapi_pagination.params import LimitOffsetPaginationParams


@dataclass
class CustomPaginationPrams:
    page: int = 0
    size: int = 10000

    def to_limit_offset(self) -> LimitOffsetPaginationParams:
        return LimitOffsetPaginationParams(
            limit=self.size,
            offset=self.size * self.page,
        )


pagination_params = using_params(CustomPaginationPrams)

Error message received:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/uvicorn/protocols/http/httptools_impl.py", line 385, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/usr/local/lib/python3.7/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/fastapi/applications.py", line 190, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/starlette/applications.py", line 111, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.7/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "/usr/local/lib/python3.7/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 566, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 227, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 41, in app
    response = await func(request)
  File "/usr/local/lib/python3.7/site-packages/fastapi/routing.py", line 189, in app
    dependant=dependant, values=values, is_coroutine=is_coroutine
  File "/usr/local/lib/python3.7/site-packages/fastapi/routing.py", line 135, in run_endpoint_function
    return await dependant.call(**values)
  File "/app/main.py", line 64, in get_studies
    return paginate(studies)
  File "/usr/local/lib/python3.7/site-packages/fastapi_pagination/paginator.py", line 11, in paginate
    limit_offset_params = params.to_limit_offset()
  File "/app/main.py", line 45, in to_limit_offset
    offset=self.size * self.page,
  File "<string>", line 5, in __init__
  File "pydantic/dataclasses.py", line 107, in pydantic.dataclasses._process_class._pydantic_post_init
pydantic.error_wrappers.ValidationError: 1 validation error for LimitOffsetPaginationParams
limit
  ensure this value is less than or equal to 100 (type=value_error.number.not_le; limit_value=100)```

How to use paginate with sqlalchemy new query syntax

Hi

I'm trying to migrate to Sqlalchemy 1.4.23 and activate the new query syntax. But can't figure out how to use paginate function with it.

fastapi-pagination==0.8.3

from sqlalchemy.future import select
from models import UserModel


class User:
    def _init__(self, db_session):
        self.db_session = session

    def get_users():
        return select(UserModel)

The endpoint looks like this:

from fastapi_pagination.ext.sqlalchemy import paginate
from fastapi_pagination import Page, Params

@router.get('/get-users')
def get_users(self, 
                       page_schema: PaginationParams = Depends(),
                       db_session: Session = Depends(get_request_db)) -> Page[UserSchema]:
    users = User(db_session).get_users()

    return paginate(users, page_schema)

I'm getting this error:

image

Also tried:

from sqlalchemy.future import select
from models import UserModel


class User:
    def _init__(self, db_session):
        self.db_session = session

    def get_users():
        return self.db_session.execute(select(UserModel))

but got this:

image

Problem with LimitOffsetPage, LimitOffsetParams and paginate

Hi!,

I have something like this:


@router.get(
    "/",
    response_model=LimitOffsetPage[ProductPlanReadModel],
)
async def get_products(
    product_query_usecase: ProductPlanQueryUseCase = Depends(
        product_query_usecase
    ),
    params: LimitOffsetParams = Depends(),
    catalogId: Optional[str] = "",
):
    try:
        products = product_query_usecase.fetch_products(catalogId)
    except Exception as err:
        logger.error(err)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        )
    return paginate(products, params)

But, when i call it, it raise an error ValueError: Page should be used with Params

Using Page and Params works fine, i got the error only when I use LimitOffset


products_1  |   File "/root/.cache/pypoetry/virtualenvs/app-MATOk_fk-py3.9/lib/python3.9/site-packages/fastapi_pagination/paginator.py", line 17, in paginate
products_1  |     return create_page(
products_1  |   File "/root/.cache/pypoetry/virtualenvs/app-MATOk_fk-py3.9/lib/python3.9/site-packages/fastapi_pagination/api.py", line 36, in create_page
products_1  |     return page_type.get().create(items, total, params)
products_1  |   File "/root/.cache/pypoetry/virtualenvs/app-MATOk_fk-py3.9/lib/python3.9/site-packages/fastapi_pagination/default.py", line 38, in create
products_1  |     raise ValueError("Page should be used with Params")
products_1  | ValueError: Page should be used with Params

Unable to install extras

Trying to install any of the extras fails on 0.52.

$ pip install fastapi-pagination[gino] fastapi-pagination[sqlalchemy] fastapi-pagination[databases] fastapi-pagination[orm] fastapi-pagination[tortoise] fastapi-pagination[all]

pip: no matches found: fastapi-pagination[gino] fastapi-pagination[sqlalchemy] fastapi-pagination[databases] fastapi-pagination[orm] fastapi-pagination[tortoise] fastapi-pagination[all]

Pagination_params not working

Hi I am trying to use fastapi-pagination

here is the sample code:

`
from typing import Any, List

from fastapi import APIRouter, Body, Depends, HTTPException

from sqlalchemy.orm import Session

from app import crud, models, schemas
from app.api import deps
from app.core.config import settings

from app.db.database import get_db

from fastapi_pagination import PaginationParams, Page
from fastapi_pagination.paginator import paginate `

router = APIRouter()

@router.post("/", response_model=schemas.Table1B)
def create_table1(*, db: Session = Depends(get_db), name: str = Body(...), about: str = Body(...)) -> Any:

table_in = schemas.Table1Create(name=name, about=about)


table = crud.tablez.create(db, obj_in=table_in)

return table

def PaginationParams1():
return {
"offset": 0,
"limit": 50
}

@router.get("/", response_model=Page[schemas.Table1B], dependencies=[Depends(PaginationParams1)])
def get_table(db: Session = Depends(get_db)) -> Any:
return paginate(db.query(models.Table1))

when executing the above code it gives following error -

raise RuntimeError("Use explicit params or pagination dependency")
RuntimeError: Use explicit params or pagination dependency

can you please let me know if this is a bug or I am doing something wrong!

Support for related objects in TortoiseORM

Does this package support related objects in TortoiseORM?
For example, paginating a list of books where each book has its author's foreign key.

Code example:

class AuthorDTO(PydanticModel):
    name: str

    class Config:
        orig_model = Author


class BookDTO(PydanticModel):
    id: int
    title: str
    added_by: AuthorDTO

    class Config:
        orig_model = Book

SQLModel integration

Hello, Do you have any plane to integrate tiangolo orm SQLModel . If yes have you any ETA.

THanks for the great work.

LimitOffsetPagination error with databases library

Hi,

    databases[postgresql]==0.4.1
    fastapi==0.63.0
    fastapi-pagination[databases]==0.5.3

I tried to use LimitOffsetPage with databases. The following code is working with Page and pagination_params.

from fastapi_pagination import Page, pagination_params
from fastapi_pagination.ext.databases import paginate

@router.get("/paginated", response_model=Page[Note], dependencies=[Depends(pagination_params)])
async def read_paginated_notes():
    return await paginate(database, notes.select())

but importing Page and pagination_params from fastapi_pagination.limit_offset generates the following error during pagination.

from fastapi_pagination.limit_offset import Page, pagination_params

  File "./demo/api/routes/notes.py", line 41, in read_paginated_notes
    return await paginate(database, notes.select())
  File "/demo/venv/lib/python3.7/site-packages/fastapi_pagination/ext/databases.py", line 35, in paginate
    return create_page(items, total, params)
  File "/demo/venv/lib/python3.7/site-packages/fastapi_pagination/api.py", line 61, in create_page
    return page_type.get().create(items, total, params)
  File "/demo/venv/lib/python3.7/site-packages/fastapi_pagination/page.py", line 27, in create
    raise ValueError(f"Page should be used with PaginationParams {type(params)}")  #  type params added.
ValueError: Page should be used with PaginationParams <class 'fastapi_pagination.params.LimitOffsetPaginationParams'>

The problem is "solved" replacing default=Page by default=LimitOffsetPage in the api.py file.

page_type: ContextVar[Type[AbstractPage]] = ContextVar("page_type", default=LimitOffsetPage)

Pagination modal is broken on pydantic 1.8

Sample traceback:

Traceback (most recent call last):
   File "app/main.py", line 18, in <module>
     from app.api.v2.servers import servers_v2_router
   File "/app/app/api/v2/servers.py", line 54, in <module>
     response_model=Page[ServerOut],
   File "/usr/local/lib/python3.8/site-packages/pydantic/generics.py", line 85, in __class_getitem__
     create_model(
   File "pydantic/main.py", line 974, in pydantic.main.create_model
   File "pydantic/main.py", line 287, in pydantic.main.ModelMetaclass.__new__
   File "pydantic/fields.py", line 391, in pydantic.fields.ModelField.infer
   File "pydantic/schema.py", line 926, in pydantic.schema.get_annotation_from_field_info
 ValueError: On field "total" the following field constraints are set but not enforced: ge.
 For more details see https://pydantic-docs.helpmanual.io/usage/schema/#unenforced-field-constraints

Downgrade to 1.7.3 solve the problem.

How do I use the customization feature?

I tried to customize FastAPI-pagination. I began implementing the AbstractPage class but I'm stuck. I don't understand how customization works. I wanted it to display the Pagination class as "links" : {"next" : 1, "page" : 0} for example instead of total":102,"page":0,"size":50 by

Can you please give me a hint on how to achieve this?

Thanks!

Links return wrong last page link

It is always +1 of what it should be. If there is 1 page it returns page 2 as last, if 10 then 11, etc.

    "total": 171,

    "page": 0,

    "size": 50,

    "links": {
        "first": "/airports/?q=international&col=name&orderby=state&page=0",
        "last": "/airports/?q=international&col=name&orderby=state&page=4",
        "self": "/airports/?q=international&col=name&orderby=state",
        "next": "/airports/?q=international&col=name&orderby=state&page=1",
        "prev": null
    }

`exclusiveMinimum` causes problems with swagger editor and Azure API Management

The use of gt to constrain the query parameters causes the openapi spec validation to fail for example in swagger editor and Azure API Management: tiangolo/fastapi#240, tiangolo/fastapi#3541
As workaround ge could be used instead, e.g.

class Page(BasePage[T], Generic[T]):
    page: conint(ge=1)  # type: ignore
    size: conint(ge=1)  # type: ignore

instead of

class Page(BasePage[T], Generic[T]):
    page: conint(gt=0)  # type: ignore
    size: conint(gt=0)  # type: ignore

Performance issues due to offset/limit paradigm on PostgreSQL database

Issue description

This line slows down SQL queries on PostgreSQL 11 significantly as it changes the execution plan.

Steps to reproduce the issue

  1. Create data
create table dummy_table_left (
 	id int primary key,
 	some_text text,
 	some_comment text
 );
 insert into dummy_table_left values 
 (1, 'two', 'three'),
 (2, 'two2', 'three'),
 (3, 'two3', 'three'),
 (4, 'two4', 'three'),
 (5, 'two5', 'three'); 
 
 create table dummy_table_right (
 	id int primary key,
 	some_text text,
 	some_comment text
 );
 insert into dummy_table_right values 
 (1, 'two', 'three2'),
 (2, 'two2', 'three3'),
 (3, 'two3', 'three4'),
 (4, 'two4', 'three5'),
 (5, 'two5', 'three6')
  1. Compare execution plan of query
explain
 select * from dummy_table_left dtl 
 join dummy_table_right dtr on dtl.some_text = dtr.some_text;

vs

explain
 select * from dummy_table_left dtl 
 join dummy_table_right dtr on dtl.some_text = dtr.some_text 
 offset 2
 limit 2;
  1. (or alternatively load more data in the tables and observe the significant increase in runtime by using explain analyze instead)

What's the expected result?

  • something similar to
Subquery Scan on row_nunber_wrapper  (cost=29.12..284.54 rows=18 width=144)
  Filter: ((row_nunber_wrapper.some_label >= 2) AND (row_nunber_wrapper.some_label <= 4))
  ->  WindowAgg  (cost=29.12..230.36 rows=3612 width=148)
        ->  Hash Join  (cost=29.12..176.18 rows=3612 width=140)
              Hash Cond: (dtl.some_text = dtr.some_text)
              ->  Seq Scan on dummy_table_left dtl  (cost=0.00..18.50 rows=850 width=68)
              ->  Hash  (cost=18.50..18.50 rows=850 width=68)
                    ->  Seq Scan on dummy_table_right dtr  (cost=0.00..18.50 rows=850 width=68)

which can be achieved with

explain 
select * from (select row_number() over (order by 1) as "some_label", * from dummy_table_left dtl 
 join dummy_table_right dtr on dtl.some_text = dtr.some_text 
) row_nunber_wrapper where some_label >= 2 and some_label <= 2 + 2;

What's the actual result?

Limit  (cost=6.05..12.10 rows=2 width=148)
  ->  WindowAgg  (cost=0.00..10930.81 rows=3612 width=148)
        ->  Nested Loop  (cost=0.00..10876.62 rows=3612 width=140)
              Join Filter: (dtl.some_text = dtr.some_text)
              ->  Seq Scan on dummy_table_left dtl  (cost=0.00..18.50 rows=850 width=68)
              ->  Materialize  (cost=0.00..22.75 rows=850 width=68)
                    ->  Seq Scan on dummy_table_right dtr  (cost=0.00..18.50 rows=850 width=68)

Additional details / screenshot

  • A nested loop on a join is significantly slower than the hash join. Adding the limit and offset impacts the actual execution plan, so this pagination technique cannot be used with constructed / joined queries (on postgres at least).
  • Presaving the result into a table would create an IO bottleneck.
  • In my use case, the proposed approach with row_number() takes 300ms compared to 30s with the implemented approach in this module.

Pagination links

Thanks for this great project! What would be the best way to customize the response to add pagination links for example as in https://jsonapi.org/examples/#pagination?

I can change the response, but I'm not sure how to best pass in request.url.path to construct the urls.

class PaginationLinks(BaseModel):
    prev: str
    next: str
    first: str
    last: str


class Page(BasePage[T], Generic[T]):
    page: conint(ge=0)  # type: ignore
    size: conint(gt=0)  # type: ignore
    links: PaginationLinks

    __params_type__ = Params  # type: ignore

    @classmethod
    def create(
        cls,
        items: Sequence[T],
        total: int,
        params: AbstractParams,
    ) -> Page[T]:
        if not isinstance(params, Params):
            raise ValueError("Page should be used with Params")

        return cls(
            total=total,
            items=items,
            page=params.page,
            size=params.size,
            links=PaginationLinks(
                ...
            ),
        )

__init__() missing 1 required positional argument: 'detail' (type=type_error)

Hello everyone
I'm receiving this weird error when browsing "/api/invoice" although I followed the guide.
The only thing here is mi response schema has a field represented by another schema

Thanks in advance for the help

fastapi_pagination Version
0.8.1
FastApi Version:

FastAPI framework, high performance, easy to learn, fast to code, ready for production"
__version__ = "0.65.2"

 INFO:     172.20.0.1:52946 - "GET /api/invoice/ HTTP/1.1" 500 Internal Server Error
backend_1       | ERROR:    Exception in ASGI application
backend_1       | Traceback (most recent call last):
backend_1       |   File "/usr/local/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py", line 369, in run_asgi
backend_1       |     result = await app(self.scope, self.receive, self.send)
backend_1       |   File "/usr/local/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 59, in __call__
backend_1       |     return await self.app(scope, receive, send)
backend_1       |   File "/usr/local/lib/python3.8/site-packages/fastapi/applications.py", line 199, in __call__
backend_1       |     await super().__call__(scope, receive, send)
backend_1       |   File "/usr/local/lib/python3.8/site-packages/starlette/applications.py", line 112, in __call__
backend_1       |     await self.middleware_stack(scope, receive, send)
backend_1       |   File "/usr/local/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
backend_1       |     raise exc from None
backend_1       |   File "/usr/local/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
backend_1       |     await self.app(scope, receive, _send)
backend_1       |   File "/usr/local/lib/python3.8/site-packages/starlette/middleware/cors.py", line 78, in __call__
backend_1       |     await self.app(scope, receive, send)
backend_1       |   File "/usr/local/lib/python3.8/site-packages/starlette/exceptions.py", line 82, in __call__
backend_1       |     raise exc from None
backend_1       |   File "/usr/local/lib/python3.8/site-packages/starlette/exceptions.py", line 71, in __call__
backend_1       |     await self.app(scope, receive, sender)
backend_1       |   File "/usr/local/lib/python3.8/site-packages/starlette/routing.py", line 580, in __call__
backend_1       |     await route.handle(scope, receive, send)
backend_1       |   File "/usr/local/lib/python3.8/site-packages/starlette/routing.py", line 241, in handle
backend_1       |     await self.app(scope, receive, send)
backend_1       |   File "/usr/local/lib/python3.8/site-packages/starlette/routing.py", line 52, in app
backend_1       |     response = await func(request)
backend_1       |   File "/usr/local/lib/python3.8/site-packages/fastapi/routing.py", line 222, in app
backend_1       |     response_data = await serialize_response(
backend_1       |   File "/usr/local/lib/python3.8/site-packages/fastapi/routing.py", line 127, in serialize_response
backend_1       |     raise ValidationError(errors, field.type_)
backend_1       | pydantic.error_wrappers.ValidationError: 4 validation errors for Page[InvoiceResponse]
backend_1       | response -> items -> 3 -> invoice_detail -> 0
backend_1       |   __init__() missing 1 required positional argument: 'detail' (type=type_error)
backend_1       | response -> items -> 4 -> invoice_detail -> 0
backend_1       |   __init__() missing 1 required positional argument: 'detail' (type=type_error)
backend_1       | response -> items -> 4 -> invoice_detail -> 1
backend_1       |   __init__() missing 1 required positional argument: 'detail' (type=type_error)
backend_1       | response -> items -> 4 -> invoice_detail -> 2
backend_1       |   __init__() missing 1 required positional argument: 'detail' (type=type_error)

Model:

class Invoice(Base):
    __tablename__ = "app_invoice"

    id = Column(Integer, primary_key=True, index=True)
    date = Column(Date)
    invoice = Column(String(20), nullable=True)
    order = Column(String(20), nullable=True)
    payment_nro = Column(String(20), nullable=True)
    payment_method = Column(String(20), nullable=True)
    created_on = Column(DateTime, default=datetime.datetime.now())
    contact_id = Column(Integer, ForeignKey("app_contact.id"))
    profesional_id = Column(Integer, ForeignKey("app_profesional.id"))
    client = relationship("Client", back_populates="invoice")
    invoice_detail = relationship("InvoiceDetail", back_populates="invoice")
    profesional = relationship("Profesional", back_populates="invoice")
    
    @hybrid_property
    def total(self):
        return func.sum(self.invoice_detail.total)

Schema:

class InvoiceResponse(BaseModel):
    id: int
    date: datetime.date
    invoice: str
    order: Optional[str]
    payment_nro: Optional[str]
    payment_method: Optional[str]
    profesional: ProfesionalResponse
    client: ClientResponse    
    created_on: datetime.datetime
    total: Optional[float] = 0.00
    invoice_detail: List[InvoiceDetailResponse]

    class Config:
        orm_mode = True

Linked Schema:

class InvoiceDetailResponse(Invoice):
    qtty: int
    price: float
    invoice_id: int
    product: ProductResponse
    total: Optional[float] = 0.00

    class Config:
        orm_mode = True

    def __init__(self, detail: InvoiceDetail, **data):
        super().__init__(total=InvoiceDetail.qtty*InvoiceDetail.price, **data)

Router:

@router.get("/api/invoice/", response_model=Page[InvoiceResponse], tags=["Invoice"])
def list_invoice(skip: int = 0, limit: int = 100,
                 db: Session = Depends(get_db),
                 current_user: User = Depends(get_current_active_user)):
    invoice = get_invoicees(db, skip=skip, limit=limit)
    # return invoice
    return paginate(invoice)

Pagination doesn't work in postgres

Trying to follow your example with databases (https://github.com/uriyyo/fastapi-pagination/blob/main/examples/pagination_databases.py) I failed with following error:

  File "c:\git\routemaker\venv\lib\site-packages\fastapi_pagination\ext\databases.py", line 13, in paginate
    total = await db.fetch_val(select([func.count()]).select_from(query))
  File "c:\git\routemaker\venv\lib\site-packages\databases\core.py", line 155, in fetch_val
    return await connection.fetch_val(query, values, column=column)
  File "c:\git\routemaker\venv\lib\site-packages\databases\core.py", line 256, in fetch_val
    return await self._connection.fetch_val(built_query, column)
  File "c:\git\routemaker\venv\lib\site-packages\databases\backends\postgres.py", line 188, in fetch_val
    row = await self.fetch_one(query)
  File "c:\git\routemaker\venv\lib\site-packages\databases\backends\postgres.py", line 168, in fetch_one
    row = await self._connection.fetchrow(query, *args)
  File "c:\git\routemaker\venv\lib\site-packages\asyncpg\connection.py", line 477, in fetchrow
    data = await self._execute(query, args, 1, timeout)
  File "c:\git\routemaker\venv\lib\site-packages\asyncpg\connection.py", line 1446, in _execute
    query, args, limit, timeout, return_status=return_status)
  File "c:\git\routemaker\venv\lib\site-packages\asyncpg\connection.py", line 1454, in __execute
    return await self._do_execute(query, executor, timeout)
  File "c:\git\routemaker\venv\lib\site-packages\asyncpg\connection.py", line 1466, in _do_execute
    stmt = await self._get_statement(query, None)
  File "c:\git\routemaker\venv\lib\site-packages\asyncpg\connection.py", line 351, in _get_statement
    statement = await self._protocol.prepare(stmt_name, query, timeout)
  File "asyncpg\protocol\protocol.pyx", line 163, in prepare
asyncpg.exceptions.PostgresSyntaxError: subquery in FROM must have an alias
HINT:  For example, FROM (SELECT ...) [AS] foo.

Fix the buy a coffee link

Appreciate today's update. Tried to buy you a coffee but kept getting denied by Paypal & error message wasn't helpful. Maybe look at Patreon or a Nano wallet?

Asyncpg issue on paginated query

Hi,
seems that asyncpg pagination doesn't manage correctly LIMIT and OFFSET clauses because the idxemphasized text used to paginate the query uses the regex result on query parameters defined on SQL Text instead the raw parameters

raw_params = params.to_raw_params()
items = await conn.fetch(
    f"{query} LIMIT ${idx + 1} OFFSET ${idx + 2}",
    *args,
    *astuple(raw_params),
    )

Pagination fails for a generator because "total" is not allowed to be None

Hi :) Thank you for the library. I am facing an issue which I hope you could help me out.

This is my script

from fastapi_pagination import Page, Params, iterables
from fastapi import Depends, FastAPI
from pydantic import BaseModel


class User(BaseModel):
    name: str

app = FastAPI()

users = (User(name="Name_"+str(i)) for i in range(1000))

@app.get(
    "/",
    response_model=Page[User],
)
def route(params: Params = Depends()):
    #return iterables.paginate(users, params, 1000) # this works
    return iterables.paginate(users, params)

Here's the traceback

WARNING:  StatReload detected file change in 'pag.py'. Reloading...
INFO:     Shutting down
INFO:     Waiting for application shutdown.
INFO:     Application shutdown complete.
INFO:     Finished server process [40003]
INFO:     Started server process [40028]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     127.0.0.1:54750 - "GET /?page=2&size=50 HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py", line 396, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/fastapi/applications.py", line 199, in __call__
    await super().__call__(scope, receive, send)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/starlette/applications.py", line 111, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/starlette/routing.py", line 566, in __call__
    await route.handle(scope, receive, send)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/starlette/routing.py", line 227, in handle
    await self.app(scope, receive, send)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/starlette/routing.py", line 41, in app
    response = await func(request)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/fastapi/routing.py", line 201, in app
    raw_response = await run_endpoint_function(
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/fastapi/routing.py", line 150, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/starlette/concurrency.py", line 34, in run_in_threadpool
    return await loop.run_in_executor(None, func, *args)
  File "/usr/lib/python3.9/concurrent/futures/thread.py", line 52, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/kishore/kishore_repositories/hx/hawkeye-poc/./pag.py", line 27, in route
    return iterables.paginate(users, params)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/fastapi_pagination/iterables.py", line 33, in paginate
    return create_page(items, total, params)  # type: ignore
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/fastapi_pagination/api.py", line 36, in create_page
    return page_type.get().create(items, total, params)
  File "/home/kishore/.cache/pypoetry/virtualenvs/hawkeye-xjjpv_py-py3.9/lib/python3.9/site-packages/fastapi_pagination/default.py", line 40, in create
    return cls(
  File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Page
total
  none is not an allowed value (type=type_error.none.not_allowed)

total: conint(ge=0) # type: ignore

The above two lines seem to be causing the problem if I'm not wrong.

Is it possible to have it as an optional argument total: int = None or total: conint(ge=0) = None # type: ignore ?

If you see my example, it works when I pass the length of the generator

return iterables.paginate(users, params, 1000) # this works

My use case is returning all rows from an OLAP. Since the number of rows are around a Million, I would be returning the rows using a generator and returning maybe 50-100 rows at a time to avoid memory overhead

I can see 2 ways to solve this.

  1. Find the length of the generator and pass it to iterables.paginate and not bother modifying fastapi-pagination. ( or for this particular use case I could get the row count and pass it without bothering to find the length of the generator)
  2. Modify fastapi-pagination to handle None as a possible parameter for total pages.

Please let me know your thoughts. I hope this is a reasonable feature to ask.

TypeError: typing.ClassVar[typing.Type[fastapi_pagination.bases.AbstractParams]] is not valid as type argument

does work with python3.9.8

268  File "/builds/app/app.py", line 5, in <module>
268    from fastapi_pagination import add_pagination
269  File "/usr/local/lib/python3.9/site-packages/fastapi_pagination/__init__.py", line 1, in <module>
270    from .api import (
271  File "/usr/local/lib/python3.9/site-packages/fastapi_pagination/api.py", line 12, in <module>
272    from .bases import AbstractPage, AbstractParams
273  File "/usr/local/lib/python3.9/site-packages/fastapi_pagination/bases.py", line 54, in <module>
274    class AbstractPage(GenericModel, Generic[T], ABC):
275  File "pydantic/main.py", line 282, in pydantic.main.ModelMetaclass.__new__
276  File "pydantic/typing.py", line 287, in pydantic.typing.resolve_annotations
277    For use of globalns and localns see the docstring for get_type_hints().
278  File "/usr/local/lib/python3.9/typing.py", line 292, in _eval_type
279    return t._evaluate(globalns, localns, recursive_guard)
280  File "/usr/local/lib/python3.9/typing.py", line 553, in _evaluate
281    type_ = _type_check(
282  File "/usr/local/lib/python3.9/typing.py", line 158, in _type_check
283    raise TypeError(f"{arg} is not valid as type argument")
284TypeError: typing.ClassVar[typing.Type[fastapi_pagination.bases.AbstractParams]] is not valid as type argument 

option to return all rows

hi, would it be possible to add a feature to the parameter to return all rows? maybe either a boolean for all rows or -1 in the size field.

Happy to submit a PR..

Page size as paginate() argument

The idea is to set page size in paginate() function. Maybe as an element of params.
So we could get this value from router argument or use some default size.

Something like this:

@router.get('', response_model=Page[ItemList])
async def get_item_list(page_size: int = 20):
    return paginate(items, page_size)

LimitOffsetParams don't work

This way pagination works fine:

from fastapi_pagination import pagination_params

When switching to limit-offset version:

from fastapi_pagination.limit_offset import pagination_params

same code and adjusted request fail with: "Page should be used with PaginationParams"
Request:

http://0.0.0.0:8080/api/v1/call_records?date_from=2021-01-01&date_till=2021-02-01&limit=50&offset=0

Endpoint:

@router.get('/call_records', response_model=Page[CallRecord], dependencies=[Depends(pagination_params)], tags=['calls'])
@handle_exceptions
async def get_call_records(date_from: datetime.date, date_till: datetime.date):
    records = await core.get_call_records(database, date_from, date_till, None)
    page = paginate(records)
    return page

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.