Páginas de perfil de piloto con estadísticas de carrera
Combina el perfil de un piloto y sus totales de carrera en una sola ficha, identificada por el número de carrera.
8 min de lectura
Las apps para aficionados, los juegos fantasy y los sitios de noticias necesitan una página por piloto. Dos llamadas te dan todo para una ficha de perfil: el piloto y sus totales de carrera.
Las dos llamadas
GET /riders/93
GET /riders/93/career-stats
/riders/{rider_number} devuelve el perfil:
{
"rider_number": 93,
"full_name": "Marc Márquez",
"nationality": "Spain",
"flag": "🇪🇸",
"birth_date": "1993-02-17",
"height_cm": 168,
"weight_kg": 59,
"team_name": "Gresini Racing MotoGP",
"image_url": null
}
/riders/{rider_number}/career-stats devuelve los totales:
{
"rider_number": 93,
"rider_name": "Marc Márquez",
"total_wins": 44,
"total_podiums": 66,
"total_points": 1302,
"world_titles": 2,
"total_races": 118
}
Los totales de carrera se calculan con las temporadas disponibles en la API, no con toda la carrera de un piloto. Indícalo en la etiqueta, por ejemplo «Desde 2024».
Obtén ambas en paralelo
import os
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass
from datetime import date
import requests
HOST = "motogp-api-championship-data-statistics.p.rapidapi.com"
HEADERS = {"X-RapidAPI-Key": os.environ["RAPIDAPI_KEY"], "X-RapidAPI-Host": HOST}
def get(path: str) -> dict:
res = requests.get(f"https://{HOST}{path}", headers=HEADERS, timeout=10)
res.raise_for_status()
return res.json()["data"]
@dataclass(frozen=True)
class RiderCard:
number: int
name: str
flag: str
team: str
age: int
wins: int
podiums: int
titles: int
races: int
@property
def podium_rate(self) -> float:
return self.podiums / self.races if self.races else 0.0
def age_on(birth: str, today: date) -> int:
born = date.fromisoformat(birth)
return today.year - born.year - ((today.month, today.day) < (born.month, born.day))
def rider_card(number: int) -> RiderCard:
with ThreadPoolExecutor(max_workers=2) as pool:
profile_f = pool.submit(get, f"/riders/{number}")
stats_f = pool.submit(get, f"/riders/{number}/career-stats")
profile, stats = profile_f.result(), stats_f.result()
return RiderCard(
number=profile["rider_number"],
name=profile["full_name"],
flag=profile["flag"],
team=profile["team_name"],
age=age_on(profile["birth_date"], date.today()),
wins=stats["total_wins"],
podiums=stats["total_podiums"],
titles=stats["world_titles"],
races=stats["total_races"],
)
card = rider_card(93)
print(f"{card.flag} #{card.number} {card.name} — {card.team}, {card.age}")
print(f"{card.wins} wins, {card.podiums} podiums in {card.races} races ({card.podium_rate:.0%})")
Crea las páginas de índice
Las páginas de perfil necesitan una lista desde la que enlazarlas:
| Página | Endpoint |
|---|---|
| Parrilla de esta temporada | GET /riders/seasons/{year}?category=MOTOGP |
| Pilotos por país | GET /riders/nationality/{nationality} (p. ej. Italy) |
| Todos los pilotos de la base de datos | GET /riders?page=1&size=200 |
Usa rider_number como slug de la URL (/riders/93/); es lo que buscan los aficionados.
Gestiona los datos que faltan
image_urlpuede sernull. Muestra el número de carrera en una insignia de color en lugar de una imagen rota.- Un número que no está en uso devuelve
404— muestra una página de «piloto no encontrado» en lugar de un error. - Los pilotos a veces cambian de número entre temporadas. Si guardas favoritos, guarda el número junto con la temporada de la que procede.