Skip to content
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

Version 0.5.0 plan #25

Closed
1 task done
greyli opened this issue Apr 19, 2021 · 5 comments
Closed
1 task done

Version 0.5.0 plan #25

greyli opened this issue Apr 19, 2021 · 5 comments
Labels

Comments

@greyli
Copy link
Member

greyli commented Apr 19, 2021

  • Class-based view

Next: Version 0.6.0 plan

@greyli greyli added the meta label Apr 19, 2021
@greyli greyli mentioned this issue Apr 20, 2021
6 tasks
@greyli greyli pinned this issue Apr 20, 2021
@lafrech
Copy link
Collaborator

lafrech commented Apr 21, 2021

Hi @greyli.

In case you'd be tempted to get inspiration from flask-smorest for the pagination feature, you may want to have a look at this thread which details an issue I'm facing with its current implementation: sqlalchemy/sqlalchemy#6333.

The feature worked with the DB ORM/ODM we were using by the time, but we might have made abusive assumptions and now the chickens come home to roost.

@greyli
Copy link
Member Author

greyli commented Apr 22, 2021

Thank you for the info @lafrech.

Adding pagination support seems a bit tricky. I will try to find an ideal solution, otherwise, we may just leave this to the user and provide a thorough guide in the documentation (It's the feature strategy of this project).

For now, without the built-in pagination support, the user can achieve pagination with the following steps:

Building a schema with the nested schema and a pagination schema

class PaginationSchema(Schema):
    pages = Integer()
    per_page = Integer()
    page = Integer()
    next = URL()
    prev = URL()
    first = URL()
    last = URL()
    current = URL()
    total = Integer()


class PetSchema(Schema):
    id = Integer()
    name = String()
    category = String()


class PetsSchema(Schema):
    pets = List(ma.Nested(PetSchema))
    pagination = Nested(PaginationSchema)

Writing a function to build pagination data

def build_pagination_schema(endpoint, pagination, **kwargs):
    per_page = pagination.per_page
    def get_page_url(page):
        return url_for(
            endpoint,
            page=page,
            per_page=per_page,
            _external=True,
            **kwargs
        )
    next = get_page_url(pagination.next_num) if pagination.has_next else ''
    prev = get_page_url(pagination.prev_num) if pagination.has_prev else ''
    return {
        'total': pagination.total,
        'pages': pagination.pages,
        'per_page': per_page,
        'page': pagination.page,
        'next': next,
        'prev': prev,
        'first': get_page_url(1),
        'last': get_page_url(pagination.pages),
        'current': get_page_url(pagination.page),
    }

Return the object list and the pagination object in the view function

Then return both the items and the pagination object in the view function (assuming use Flask-SQLAlchemy):

class PaginationQuerySchema(Schema):
    page = Integer(missing=1)
    per_page = Integer(missing=20)


@app.get('/pets')
@input(PaginationQuerySchema, 'query')
@output(PetsSchema)
def get_pets(query):
    pagination = Pet.query.paginate(query['page'], query['per_page'])
    pets = pagination.items
    return {
        'pets': pets,
        'pagination': build_pagination_schema('get_pets', pagination)
    }

@greyli
Copy link
Member Author

greyli commented Apr 22, 2021

Moved pagination to 0.6.0 plan.

@lafrech
Copy link
Collaborator

lafrech commented Apr 22, 2021

The situation is not as bad as I first thought. Being unfamiliar with the internals, I found the linked conversation very instructive. But ultimately, the pagination feature in flask-smorest is not broken. It just uses a feature that is being un-recommended in SQLALchemy that uses offsets for pagination. The same feature Flask-SQLAlchemy uses, I suppose (didn't check but pretty sure cause "what else ?"). An automatic feature can't do better than this.

flask-smorest also aims at providing all it can without making too many assumptions and without blocking other use cases.

It offers two modes:

  • raw mode where we provide a schema, arguments injection and auto-doc, while pagination is left to user in view func
  • integrated mode where the view returns a paginable object and everything is automatic

The feature is of course optional. Almost but not exactly independent: to achieve auto-doc, it needs to know which response (which status code) is the one that gets the pagination (which is the "normal path", as opposed to error paths). This is possible because the response decorator is cooperative and marks the normal path so that at doc building time, all needed info is available.

Depending on the object return by the data source driver, the paginator class can be more or less challenging to achieve. The example we provide happens to work with pymongo (<4) and SQLAlchemy (1.0 API but not removed in 2.0) but it is not as generic as I hoped. Nothing really new.

@greyli
Copy link
Member Author

greyli commented Apr 27, 2021

Version 0.5.0 released.

@greyli greyli closed this as completed Apr 27, 2021
@greyli greyli mentioned this issue Apr 27, 2021
1 task
@greyli greyli unpinned this issue Apr 27, 2021
@greyli greyli mentioned this issue May 11, 2021
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants