Start learning free

LESSON 77 OF 188 · BACKEND: APIS WITH A DATABASE

Pages of Results in Python

Practice

A real shop can have thousands of products, far too many for one answer. So clients ask for one page at a time: /products?page=2&per_page=3 means pages of 3 products, and the second one. The answer also gives the total, how many products match in all, and next_page, the page to ask for next, or null when there is none.

SQL cuts out one page with LIMIT and OFFSET: OFFSET skips rows, then LIMIT gives at most that many of the rows after them. To count the rows a query gives, wrap it in SELECT COUNT(*) FROM (...). On the orders table, with 5 orders per page:

-- page 3 of the new orders: skip 10, give the next 5
SELECT * FROM orders WHERE status = 'new' LIMIT 5 OFFSET 10
-- how many new orders there are in all
SELECT COUNT(*) FROM (SELECT * FROM orders WHERE status = 'new')

In Flask, request.args.get takes a default as its second argument: request.args.get("limit", 5, type=int) gives 5 when the request has no limit.

Your GET /products must give these answers:

GET /products?page=2&per_page=3
    →  200  {"products": [Pen, Plant, Teapot], "total": 8, "next_page": 3}
GET /products?page=3&per_page=3
    →  200  {"products": [Stapler, Gift card], "total": 8, "next_page": null}
GET /products?page=4&per_page=3
    →  200  {"products": [], "total": 8, "next_page": null}
GET /products?category=office&per_page=2
    →  200  {"products": [Notebook, Pen], "total": 3, "next_page": 2}
GET /products?category=office&per_page=2&page=2
    →  200  {"products": [Stapler], "total": 3, "next_page": null}
GET /products?max_price=10&per_page=3
    →  200  {"products": [Notebook, Pen, Stapler], "total": 3, "next_page": null}
GET /products
    →  200  {"products": [all 8 products], "total": 8, "next_page": null}
GET /products?page=0&per_page=3
    →  400  {"error": "page and per_page must be 1 or more"}

Each product in "products" is the full object, like {"id": 4, "name": "Pen", "price": 2, "category": "office", "stock": 120}.

Your task: make GET /products answer one page at a time, with the filters still working. Read page (1 if missing) and per_page (10 if missing), and answer a dictionary with the page's "products", the "total" and the "next_page". A page or per_page below 1 gets a 400.


Assignment
Follow the Coding Tutorial to count the matching products, give the answer its new shape, and cut one page out with LIMIT and OFFSET.


Hint
Page page starts after (page - 1) * per_page rows. Count the total before you add LIMIT to the query, or it will count only one page.


STEP 1 OF 10
    Ctrl + Enter to check

    Db Pagination in Python

    Keep going with Python1,600+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free