← Todas las guías

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áginaEndpoint
Parrilla de esta temporadaGET /riders/seasons/{year}?category=MOTOGP
Pilotos por paísGET /riders/nationality/{nationality} (p. ej. Italy)
Todos los pilotos de la base de datosGET /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_url puede ser null. 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.
Siguiente guía → Calendario de la temporada, próxima carrera y resultados