50% OFF Plus
--:--:--
¡Obtener!

Servir archivos estáticos

Intermedio
FastAPI
FastAPI
Actualizado: 01/07/2025

¡Desbloquea el curso de FastAPI completo!

IA
Ejercicios
Certificado
Entrar

Mira la lección en vídeo

Accede al vídeo completo de esta lección y a más contenido exclusivo con el Plan Plus.

Desbloquear Plan Plus

Configuración de StaticFiles

FastAPI incluye soporte nativo para servir archivos estáticos como CSS, JavaScript, imágenes y otros recursos que necesitan las páginas web. Estos archivos no cambian dinámicamente y se sirven directamente al navegador sin procesamiento adicional.

Para habilitar el servicio de archivos estáticos, necesitamos usar la clase StaticFiles de FastAPI y montarla en nuestra aplicación. Esta configuración permite que el servidor web sirva archivos desde un directorio específico de nuestro proyecto.

Instalación de dependencias

Antes de configurar los archivos estáticos, necesitamos instalar python-multipart, que es requerido por StaticFiles:

pip install python-multipart

Estructura de directorios

La práctica habitual es crear un directorio llamado static en la raíz del proyecto para almacenar todos los recursos estáticos:

mi_proyecto/
├── main.py
├── templates/
│   └── index.html
└── static/
    ├── css/
    │   └── styles.css
    ├── js/
    │   └── script.js
    └── images/
        └── logo.png

Configuración básica

Para configurar StaticFiles en FastAPI, importamos la clase y la montamos en nuestra aplicación usando el método mount():

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from fastapi.requests import Request

app = FastAPI()

# Configurar archivos estáticos
app.mount("/static", StaticFiles(directory="static"), name="static")

# Configurar templates
templates = Jinja2Templates(directory="templates")

@app.get("/")
async def home(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

El método mount() recibe tres parámetros importantes:

  • Ruta de montaje ("/static"): La URL base donde estarán disponibles los archivos
  • StaticFiles con el directorio local (directory="static")
  • Nombre (name="static"): Identificador interno para referenciar esta configuración

Acceso a los archivos estáticos

Una vez configurado, los archivos del directorio static estarán accesibles a través de URLs que siguen el patrón /static/ruta_del_archivo:

  • static/css/styles.csshttp://localhost:8000/static/css/styles.css
  • static/js/script.jshttp://localhost:8000/static/js/script.js
  • static/images/logo.pnghttp://localhost:8000/static/images/logo.png

Ejemplo completo con archivos CSS

Creemos un ejemplo práctico con un archivo CSS. Primero, el archivo styles.css en static/css/:

/* static/css/styles.css */
body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 20px;
    background-color: #f5f5f5;
}

.container {
    max-width: 800px;
    margin: 0 auto;
    background-color: white;
    padding: 30px;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

h1 {
    color: #333;
    text-align: center;
}

El template HTML que usa este CSS:

<!-- templates/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Mi Aplicación FastAPI</title>
    <link rel="stylesheet" href="/static/css/styles.css">
</head>
<body>
    <div class="container">
        <h1>Bienvenido a FastAPI</h1>
        <p>Esta página usa archivos estáticos para el diseño.</p>
    </div>
</body>
</html>

Configuración con múltiples directorios

También es posible montar múltiples directorios estáticos con diferentes rutas de acceso:

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles

app = FastAPI()

# Archivos CSS y JS
app.mount("/assets", StaticFiles(directory="static"), name="assets")

# Imágenes en directorio separado
app.mount("/media", StaticFiles(directory="uploads"), name="media")

Esta configuración permite organizar mejor los recursos según su tipo y tener URLs más específicas para cada categoría de archivos estáticos.

Enlazar CSS y JavaScript en templates

Guarda tu progreso

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

Una vez configurados los archivos estáticos, el siguiente paso es enlazarlos correctamente en nuestros templates HTML. FastAPI con Jinja2 ofrece varias formas de referenciar estos recursos, desde enlaces directos hasta el uso de funciones auxiliares que generan las URLs automáticamente.

Enlaces directos a archivos estáticos

La forma más directa de enlazar archivos CSS y JavaScript es usando rutas absolutas que apunten al directorio estático configurado:

<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mi Aplicación</title>
    
    <!-- Enlace directo a CSS -->
    <link rel="stylesheet" href="/static/css/styles.css">
    <link rel="stylesheet" href="/static/css/components.css">
</head>
<body>
    <div class="container">
        <h1>Contenido de la página</h1>
    </div>
    
    <!-- Enlaces directos a JavaScript -->
    <script src="/static/js/utils.js"></script>
    <script src="/static/js/main.js"></script>
</body>
</html>

Uso de url_for para generar URLs

Jinja2 proporciona la función url_for() que genera automáticamente las URLs correctas basándose en el nombre que asignamos al montar los archivos estáticos. Esta aproximación es más robusta porque se adapta automáticamente si cambiamos la configuración:

<!-- templates/dashboard.html -->
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Dashboard</title>
    
    <!-- Usando url_for para CSS -->
    <link rel="stylesheet" href="{{ url_for('static', path='/css/dashboard.css') }}">
    <link rel="stylesheet" href="{{ url_for('static', path='/css/forms.css') }}">
</head>
<body>
    <div class="dashboard">
        <h1>Panel de Control</h1>
        <div class="widgets">
            <!-- Contenido del dashboard -->
        </div>
    </div>
    
    <!-- Usando url_for para JavaScript -->
    <script src="{{ url_for('static', path='/js/charts.js') }}"></script>
    <script src="{{ url_for('static', path='/js/dashboard.js') }}"></script>
</body>
</html>

El parámetro 'static' corresponde al nombre que definimos en la configuración (name="static"), y path especifica la ruta relativa dentro del directorio estático.

Ejemplo práctico con múltiples archivos

Creemos un ejemplo completo que demuestre cómo organizar y enlazar múltiples archivos CSS y JavaScript. Primero, los archivos estáticos:

static/css/base.css:

/* Estilos base para toda la aplicación */
* {
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    line-height: 1.6;
    margin: 0;
    padding: 0;
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px;
}

static/css/forms.css:

/* Estilos específicos para formularios */
.form-group {
    margin-bottom: 20px;
}

.form-control {
    width: 100%;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 16px;
}

.btn {
    background-color: #007bff;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

static/js/validation.js:

// Funciones de validación de formularios
function validateEmail(email) {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
}

function validateForm(formData) {
    const errors = [];
    
    if (!formData.name || formData.name.trim().length < 2) {
        errors.push('El nombre debe tener al menos 2 caracteres');
    }
    
    if (!validateEmail(formData.email)) {
        errors.push('El email no tiene un formato válido');
    }
    
    return errors;
}

static/js/app.js:

// Funcionalidad principal de la aplicación
document.addEventListener('DOMContentLoaded', function() {
    const forms = document.querySelectorAll('form');
    
    forms.forEach(form => {
        form.addEventListener('submit', function(e) {
            e.preventDefault();
            
            const formData = new FormData(form);
            const data = Object.fromEntries(formData);
            
            const errors = validateForm(data);
            
            if (errors.length > 0) {
                showErrors(errors);
            } else {
                submitForm(data);
            }
        });
    });
});

function showErrors(errors) {
    const errorContainer = document.getElementById('errors');
    errorContainer.innerHTML = errors.map(error => 
        `<div class="alert alert-error">${error}</div>`
    ).join('');
}

Template que utiliza todos los archivos

templates/contact.html:

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Contacto - Mi Aplicación</title>
    
    <!-- Archivos CSS en orden de importancia -->
    <link rel="stylesheet" href="{{ url_for('static', path='/css/base.css') }}">
    <link rel="stylesheet" href="{{ url_for('static', path='/css/forms.css') }}">
</head>
<body>
    <div class="container">
        <h1>Formulario de Contacto</h1>
        
        <div id="errors"></div>
        
        <form id="contactForm">
            <div class="form-group">
                <label for="name">Nombre:</label>
                <input type="text" id="name" name="name" class="form-control" required>
            </div>
            
            <div class="form-group">
                <label for="email">Email:</label>
                <input type="email" id="email" name="email" class="form-control" required>
            </div>
            
            <div class="form-group">
                <label for="message">Mensaje:</label>
                <textarea id="message" name="message" class="form-control" rows="5" required></textarea>
            </div>
            
            <button type="submit" class="btn">Enviar Mensaje</button>
        </form>
    </div>
    
    <!-- JavaScript al final del body para mejor rendimiento -->
    <script src="{{ url_for('static', path='/js/validation.js') }}"></script>
    <script src="{{ url_for('static', path='/js/app.js') }}"></script>
</body>
</html>

Ruta de FastAPI correspondiente

Para que este template funcione correctamente, necesitamos la ruta correspondiente en FastAPI:

from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

app = FastAPI()

# Configuración de archivos estáticos
app.mount("/static", StaticFiles(directory="static"), name="static")

# Configuración de templates
templates = Jinja2Templates(directory="templates")

@app.get("/contact")
async def contact_page(request: Request):
    return templates.TemplateResponse("contact.html", {"request": request})

Buenas prácticas para enlazar archivos

Al enlazar archivos CSS y JavaScript en templates, es recomendable seguir estas prácticas:

  • Orden de carga: Los archivos CSS van en el <head>, los JavaScript al final del <body>
  • Dependencias: Cargar primero los archivos base y luego los específicos
  • Consistencia: Usar siempre url_for() o siempre rutas directas, no mezclar ambos enfoques
  • Organización: Agrupar archivos relacionados en subdirectorios (css/, js/, images/)

Esta configuración permite que nuestras páginas web tengan estilos visuales atractivos y funcionalidad interactiva, manteniendo una estructura organizada y fácil de mantener.

Aprendizajes de esta lección de FastAPI

  • Comprender cómo configurar la clase StaticFiles para servir archivos estáticos en FastAPI.
  • Organizar la estructura de directorios para recursos estáticos en un proyecto FastAPI.
  • Enlazar correctamente archivos CSS y JavaScript en templates HTML usando rutas absolutas y la función url_for.
  • Implementar múltiples directorios estáticos con diferentes rutas de acceso para una mejor organización.
  • Aplicar buenas prácticas en la carga y organización de archivos estáticos para mejorar la mantenibilidad y rendimiento.

Completa este curso de FastAPI y certifícate

Únete a nuestra plataforma de cursos de programación y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración