miguelgrinberg / APIFairy

A minimalistic API framework built on top of Flask, Marshmallow and friends.
MIT License
323 stars 30 forks source link

Add pagination to response. #62

Closed Muhammad-Nasr closed 2 years ago

Muhammad-Nasr commented 2 years ago

I need you help If I can. I am working on a project for api. I am using apifairy for your reference. It is very good and simple. The company wants me to display a data in a format

return Response({
           'result': plants_schema.dump(plants.items),
            'pagination':{
                'count':plants.total,
                'pages':plants.pages,
                'page':plants.page,
                # 'per_page':plants.per_page,
                # 'has_next':plants.has_next,
                # 'has_prev':plants.has_prev,
            },
            'message':"Plants retrieved successfully!"

        }), status=200)

I now can't to add pagination to my schema

{
        "arrival_date": "2022-09-17 20:36Z",
        "id": 1,
        "location": "cairo",
        "name": "honda",
        "package": "yes",
        "price": 50.0,
        "quantity": 12,
        "status": "active",

        "total_quantity": 40,
        "type": "seeds"
    },

I tried to follow your pagination decorator in microblog api but I am in a trouble. It is a high level and I can't understand well. and I am using sqlalchemy model If I could ask, If there a simple way for me I could use to solve this problem. sorry for some unclarifications.

Originally posted by @Muhammad-Nasr in https://github.com/miguelgrinberg/APIFairy/issues/49#issuecomment-1250244206

miguelgrinberg commented 2 years ago

Using a decorator is just a convenience. You can define a schema that includes your data and your pagination, and then return a data structure that matches that schema.

Muhammad-Nasr commented 2 years ago

I can't find a way to do the same structure in the schema I can return my structure out of the @response but then no documnetation for response.

Muhammad-Nasr commented 2 years ago

I can't make the same structure pagination is included in every object. I want to make it independent from data.

the code class ItemSchema(ma.Schema): class Meta: model = Item ordered = True description = 'This schema represents an item model'

total_quantity = ma.String()
status = ma.String(required=True,
                   validate=validate.OneOf(
                       ['archived', 'active']),
                   description="the item status")

supplier_id = ma.String(dump_only=True)  # read only
page = ma.String(missing=1)
per_page = ma.String(dump_default=4)
pagination = ma.Nested(PaginationItemSchema)

@validates("quantity")
def validate_quantity(self, n):
    if n < 0:
        raise ValidationError("Quantity must be greater than 0.")

or this

class PagingationSchema(ItemSchema): page = ma.Int(default=4) per_page = ma.Int(default=3)

[

{
    "arrival_date": "2022-09-18 06:47Z",
    "id": "4",
    "location": "cairo",
    "name": "honda",
    "package": "yes",
    "page": 4,
    "per_page": 3,
    "price": "50.0",
    "quantity": "12",
    "status": "Status.ARCHIVED",
    "supplier_id": null,
    "total_quantity": "20",
    "type": "Type.SEEDS"
},
{
    "arrival_date": "2022-09-18 06:48Z",
    "id": "5",
    "location": "cairo",
    "name": "honda",
    "package": "yes",
    "page": 4,
    "per_page": 3,
    "price": "50.0",
    "quantity": "12",
    "status": "Status.ARCHIVED",
    "supplier_id": null,
    "total_quantity": "20",
    "type": "Type.SEEDS"
},

]

please tutor If you have a solution for me

miguelgrinberg commented 2 years ago

This happens because you have the item and the pagination elements all in a single schema. You should use nested schemas. Something like this:

    class PaginatedSchema(ma.Schema):
        class Meta:
            ordered = True

        pagination = ma.Nested(PaginationSchema)
        data = ma.Nested(ItemSchema, many=True)

Then you can define two separate schemas, one for the pagination data and another one for the item data.

Muhammad-Nasr commented 2 years ago

I get empty objects {} in the response . I can't pass the data to schemas for response

pagination = PaginatedSchema(many=True)

@items.route('/items', methods=['GET'])
@response(paginagion)
@ other_responses({404: "Items not found"})
def all():
    """Retrieve all Items"""

    items = Item.query.all()   
    return items                       ## I don't know how to pass pages in response

class ItemSchema(ma.Schema):
    class Meta:
        model = Item
        ordered = True
        description = 'This schema represents an item model'

    id = ma.String(dump_only=True)
    name = ma.String(required=True, description='name of the item',
                     error_messages={"required": "Item name is required"},
                     validate=validate.Length(min=3, max=64))

    quantity = ma.String(required=True,
                         error_messages={

    total_quantity = ma.String()
    status = ma.String(required=True,
                       validate=validate.OneOf(
                           ['archived', 'active']),
                       description="the item status")

##
class PagingationSchema(ma.Schema):
    page = ma.Int(default=4)
    per_page = ma.Int(default=3)

class PaginatedSchema(ma.Schema):
    class Meta:
        ordered = True

    pagination = ma.Nested(PagingationSchema)
    data = ma.Nested(ItemSchema, many=True)
miguelgrinberg commented 2 years ago
@items.route('/items', methods=['GET'])
@response(paginagion)
@ other_responses({404: "Items not found"})
def all():
    """Retrieve all Items"""

    items = Item.query.all()   
    return {
        'data': items,
        'pagination': {
            'page': page,
            'per_page': per_page,
        },
    }
Muhammad-Nasr commented 2 years ago

Thank you very much Mr. @miguelgrinberg It's worked well, you are a decent tutor. You helped me a lot this is my first api project. I just needed to use apifairy for your recommendation It was a nice lesson for me.