Python · API · Початковий рівень

Пагінація

5 завдань

Проходьте по багатосторінкових відповідях API, щоб зібрати всі результати.

Як працює пагінація

#
API рідко повертає тисячі записів в одній відповіді — це було б повільно та марнотратно. Натомість результати розбиваються на сторінки. Ендпоінт /api/products/ за замовчуванням повертає до 20 елементів на сторінку, але в каталозі загалом 372 продукти. Кожна відповідь із пагінацією містить чотири верхньорівневі поля: ```python data = response.json() data['count'] # 372 — усього елементів по ВСІХ сторінках data['next'] # URL наступної сторінки або null, якщо це остання data['previous'] # URL попередньої сторінки або null, якщо це перша data['results'] # список елементів на поточній сторінці ``` Для навігації по сторінках є два варіанти: Варіант 1 — слідуйте за URL next. Сервер будує URL за вас, тому не потрібно обчислювати номери сторінок: ```python url = f'{BASE_URL}/api/products/' while url: data = requests.get(url).json() for product in data['results']: print(product['name']) url = data['next'] # None, коли сторінок більше немає ``` Варіант 2 — обчисліть загальну кількість сторінок і ітеруйте з лічильником: ```python PAGE_SIZE = 20 first = requests.get(f'{BASE_URL}/api/products/', params={'page_size': PAGE_SIZE}).json() total_pages = -(-first['count'] // PAGE_SIZE) # ділення з округленням вгору for page in range(1, total_pages + 1): data = requests.get( f'{BASE_URL}/api/products/', params={'page': page, 'page_size': PAGE_SIZE}, ).json() # обробіть data['results'] ``` Слідувати за next простіше та надійніше — це працює навіть якщо загальна кількість змінюється під час пагінації. Підхід з лічильником корисний, коли заздалегідь потрібно знати кількість сторінок, наприклад щоб показати індикатор прогресу.

Паттерни пагінації

#
Зберіть усі назви продуктів по всьому каталогу: ```python import requests BASE_URL = 'https://apilearn.tukas.dev' all_names = [] url = f'{BASE_URL}/api/products/' while url: data = requests.get(url).json() for product in data['results']: all_names.append(product['name']) url = data['next'] print(f'Зібрано {len(all_names)} продуктів') ``` Пагінація працює з фільтрами — URL next зберігає всі ваші параметри: ```python url = f'{BASE_URL}/api/products/' params = {'category': 'kitchen', 'ordering': 'price'} all_products = [] while url: data = requests.get(url, params=params).json() all_products.extend(data['results']) url = data['next'] params = {} # params вже закодовані в наступному URL print(f'Товарів kitchen: {len(all_products)}') ``` Примітка: після того як починаєте слідувати за next, очищайте params — наступний URL вже містить їх. Якщо передати params знову, деякі значення можуть задублюватись у URL. Знайдіть найдорожчий продукт по всіх сторінках: ```python # Ефективніше: сортування за спаданням і взяття першого результату data = requests.get( f'{BASE_URL}/api/products/', params={'ordering': '-price', 'page_size': 1}, ).json() most_expensive = data['results'][0] print(most_expensive['name'], most_expensive['price']) ``` Коли потрібне одне екстремальне значення (максимум, мінімум), нехай сервер зробить роботу з ordering і page_size=1. Отримувати всі сторінки лише щоб знайти максимум — марнотратство.

Довідник пагінації

#
Поля відповіді з пагінацією: ``` count int Усього елементів по всіх сторінках next str | null URL наступної сторінки; null на останній previous str | null URL попередньої сторінки; null на першій results list Елементи на поточній сторінці ``` Параметри пагінації: ``` page int Номер сторінки (за замовчуванням: 1) page_size int Елементів на сторінці (за замовчуванням: 20) ``` Формула для загальної кількості сторінок: ```python import math total_pages = math.ceil(count / page_size) # або без math: total_pages = -(-count // page_size) # трюк з діленням вгору ``` Патерни циклів: ```python # Слідувати за next (рекомендується) url = f'{BASE_URL}/api/products/' while url: data = requests.get(url).json() # обробіть data['results'] url = data['next'] # Лічильник сторінок for page in range(1, total_pages + 1): data = requests.get(url, params={'page': page, 'page_size': 20}).json() # обробіть data['results'] ```
01

Отримати конкретну сторінку

#

Отримайте 3-тю сторінку списку продуктів з page_size=10. Виведіть назву кожного продукту на цій сторінці.

import requests

BASE_URL = 'https://apilearn.tukas.dev'

# Отримайте 3-тю сторінку і виведіть назви продуктів
Рішення
import requests

BASE_URL = 'https://apilearn.tukas.dev'

params = {'page': 3, 'page_size': 10}
response = requests.get(f'{BASE_URL}/api/products/', params=params)
for product in response.json()['results']:
    print(product['name'])
02

Обчислити кількість сторінок

#

Отримайте список продуктів з page_size=20. Обчисліть та виведіть загальну кількість сторінок, необхідних для перегляду всіх продуктів.

import requests

BASE_URL = 'https://apilearn.tukas.dev'

# Обчисліть кількість сторінок для page_size=20
Рішення
import requests
import math

BASE_URL = 'https://apilearn.tukas.dev'

PAGE_SIZE = 20
data = requests.get(f'{BASE_URL}/api/products/', params={'page_size': PAGE_SIZE}).json()
total_pages = math.ceil(data['count'] / PAGE_SIZE)
print(f'{data["count"]} продуктів на {total_pages} сторінках')
03

Зібрати всі продукти категорії

#

Зберіть усі продукти в категорії "kitchen" до списку, слідуючи за URL next. Виведіть загальну кількість зібраних продуктів.

import requests

BASE_URL = 'https://apilearn.tukas.dev'

all_products = []
url = f'{BASE_URL}/api/products/'
params = {'category': 'kitchen'}

# Пройдіть усі сторінки товарів kitchen
Рішення
import requests

BASE_URL = 'https://apilearn.tukas.dev'

all_products = []
url = f'{BASE_URL}/api/products/'
params = {'category': 'kitchen'}

while url:
    data = requests.get(url, params=params).json()
    all_products.extend(data['results'])
    url = data['next']
    params = {}

print(len(all_products))
04

Зібрати всі назви продуктів

#

Зберіть назви всіх продуктів у каталозі (усі сторінки) до списку. Виведіть загальну кількість і назву останнього продукту в списку.

import requests

BASE_URL = 'https://apilearn.tukas.dev'

# Зберіть усі назви продуктів по всіх сторінках
Рішення
import requests

BASE_URL = 'https://apilearn.tukas.dev'

all_names = []
url = f'{BASE_URL}/api/products/'

while url:
    data = requests.get(url).json()
    for product in data['results']:
        all_names.append(product['name'])
    url = data['next']

print(len(all_names))
print(all_names[-1])
05

Знайти найдорожчий продукт

#

Знайдіть найдорожчий продукт у каталозі без отримання всіх сторінок. Виведіть його назву і ціну.

import requests

BASE_URL = 'https://apilearn.tukas.dev'

# Ефективно знайдіть найдорожчий продукт
Рішення
import requests

BASE_URL = 'https://apilearn.tukas.dev'

params = {'ordering': '-price', 'page_size': 1}
data = requests.get(f'{BASE_URL}/api/products/', params=params).json()
product = data['results'][0]
print(product['name'])
print(product['price'])