BIBLIOTECA DJANGO

CÓDIGO COMPLETO - Parte 5 y 6

✅ 7 Vistas | ✅ 8 Templates | ✅ CSS (284 líneas) | ✅ JS (238 líneas)

Volver al Inicio
TODOS LOS CÓDIGOS COMPLETOS

Esta página contiene TODO el código sin omisiones. Navega por las pestañas y copia cada archivo.

📁 Crear carpetas: templates/base, templates/libros, static/css, static/js, media/portadas, media/autores

libros/views.py (217 líneas - 7 vistas)
from django.shortcuts import render, get_object_or_404
from django.db.models import Count, Avg, Q
from .models import Libro, Autor, Categoria, Editorial, Prestamo

def inicio(request):
    """Vista principal con estadísticas del sistema"""
    total_libros = Libro.objects.count()
    total_autores = Autor.objects.count()
    total_categorias = Categoria.objects.filter(activa=True).count()
    libros_disponibles = Libro.objects.filter(estado='disponible').count()
    prestamos_activos = Prestamo.objects.filter(estado='activo').count()
    
    libros_destacados = Libro.objects.filter(
        calificacion__gte=4.0
    ).order_by('-calificacion')[:6]
    
    ultimos_libros = Libro.objects.order_by('-fecha_publicacion')[:6]
    
    context = {
        'total_libros': total_libros,
        'total_autores': total_autores,
        'total_categorias': total_categorias,
        'libros_disponibles': libros_disponibles,
        'prestamos_activos': prestamos_activos,
        'libros_destacados': libros_destacados,
        'ultimos_libros': ultimos_libros,
    }
    return render(request, 'libros/inicio.html', context)

def lista_libros(request):
    """Listado de todos los libros con filtros"""
    libros = Libro.objects.select_related('autor', 'editorial').prefetch_related('categorias')
    
    # Filtros
    categoria_id = request.GET.get('categoria')
    autor_id = request.GET.get('autor')
    estado = request.GET.get('estado')
    busqueda = request.GET.get('q')
    
    if categoria_id:
        libros = libros.filter(categorias__id=categoria_id)
    if autor_id:
        libros = libros.filter(autor__id=autor_id)
    if estado:
        libros = libros.filter(estado=estado)
    if busqueda:
        libros = libros.filter(
            Q(titulo__icontains=busqueda) |
            Q(isbn__icontains=busqueda) |
            Q(autor__nombre__icontains=busqueda)
        )
    
    # Para los selectores de filtro
    categorias = Categoria.objects.filter(activa=True)
    autores = Autor.objects.all().order_by('nombre')
    estados = Libro.ESTADO_CHOICES
    
    context = {
        'libros': libros,
        'categorias': categorias,
        'autores': autores,
        'estados': estados,
        'categoria_seleccionada': categoria_id,
        'autor_seleccionado': autor_id,
        'estado_seleccionado': estado,
        'busqueda': busqueda,
    }
    return render(request, 'libros/lista_libros.html', context)

def detalle_libro(request, id):
    """Detalles completos de un libro específico"""
    libro = get_object_or_404(
        Libro.objects.select_related('autor', 'editorial').prefetch_related('categorias'),
        id=id
    )
    
    # Libros relacionados (mismo autor o categorías similares)
    libros_relacionados = Libro.objects.filter(
        Q(autor=libro.autor) | Q(categorias__in=libro.categorias.all())
    ).exclude(id=libro.id).distinct()[:4]
    
    context = {
        'libro': libro,
        'libros_relacionados': libros_relacionados,
    }
    return render(request, 'libros/detalle_libro.html', context)

def lista_autores(request):
    """Listado de todos los autores con estadísticas"""
    autores = Autor.objects.annotate(
        total_libros=Count('libro'),
        calificacion_promedio=Avg('libro__calificacion')
    ).order_by('nombre')
    
    busqueda = request.GET.get('q')
    if busqueda:
        autores = autores.filter(
            Q(nombre__icontains=busqueda) |
            Q(pais_origen__icontains=busqueda)
        )
    
    context = {
        'autores': autores,
        'busqueda': busqueda,
    }
    return render(request, 'libros/lista_autores.html', context)

def detalle_autor(request, id):
    """Detalles de un autor y sus libros"""
    autor = get_object_or_404(Autor, id=id)
    libros = Libro.objects.filter(autor=autor).prefetch_related('categorias')
    
    # Estadísticas del autor
    total_libros = libros.count()
    calificacion_promedio = libros.aggregate(Avg('calificacion'))['calificacion__avg'] or 0
    
    context = {
        'autor': autor,
        'libros': libros,
        'total_libros': total_libros,
        'calificacion_promedio': round(calificacion_promedio, 1),
    }
    return render(request, 'libros/detalle_autor.html', context)

def busqueda_avanzada(request):
    """Búsqueda avanzada con múltiples filtros"""
    libros = Libro.objects.select_related('autor', 'editorial').prefetch_related('categorias')
    
    # Filtros avanzados
    titulo = request.GET.get('titulo')
    autor = request.GET.get('autor')
    categoria = request.GET.get('categoria')
    editorial = request.GET.get('editorial')
    año_desde = request.GET.get('año_desde')
    año_hasta = request.GET.get('año_hasta')
    precio_min = request.GET.get('precio_min')
    precio_max = request.GET.get('precio_max')
    calificacion_min = request.GET.get('calificacion_min')
    
    if titulo:
        libros = libros.filter(titulo__icontains=titulo)
    if autor:
        libros = libros.filter(autor__nombre__icontains=autor)
    if categoria:
        libros = libros.filter(categorias__id=categoria)
    if editorial:
        libros = libros.filter(editorial__id=editorial)
    if año_desde:
        libros = libros.filter(fecha_publicacion__year__gte=año_desde)
    if año_hasta:
        libros = libros.filter(fecha_publicacion__year__lte=año_hasta)
    if precio_min:
        libros = libros.filter(precio__gte=precio_min)
    if precio_max:
        libros = libros.filter(precio__lte=precio_max)
    if calificacion_min:
        libros = libros.filter(calificacion__gte=calificacion_min)
    
    categorias = Categoria.objects.filter(activa=True)
    editoriales = Editorial.objects.all().order_by('nombre')
    
    context = {
        'libros': libros,
        'categorias': categorias,
        'editoriales': editoriales,
        'filtros': request.GET,
    }
    return render(request, 'libros/busqueda_avanzada.html', context)

def estadisticas(request):
    """Dashboard con métricas y estadísticas del sistema"""
    # Estadísticas generales
    total_libros = Libro.objects.count()
    total_autores = Autor.objects.count()
    total_categorias = Categoria.objects.count()
    total_editoriales = Editorial.objects.count()
    
    # Estadísticas de libros
    libros_por_estado = Libro.objects.values('estado').annotate(
        total=Count('id')
    ).order_by('-total')
    
    # Top 10 autores con más libros
    top_autores = Autor.objects.annotate(
        total_libros=Count('libro')
    ).order_by('-total_libros')[:10]
    
    # Top 10 categorías más populares
    top_categorias = Categoria.objects.annotate(
        total_libros=Count('libro')
    ).order_by('-total_libros')[:10]
    
    # Libros mejor calificados
    mejores_libros = Libro.objects.filter(
        calificacion__gte=4.0
    ).order_by('-calificacion')[:10]
    
    # Estadísticas de préstamos
    total_prestamos = Prestamo.objects.count()
    prestamos_activos = Prestamo.objects.filter(estado='activo').count()
    prestamos_retrasados = Prestamo.objects.filter(estado='retrasado').count()
    
    context = {
        'total_libros': total_libros,
        'total_autores': total_autores,
        'total_categorias': total_categorias,
        'total_editoriales': total_editoriales,
        'libros_por_estado': libros_por_estado,
        'top_autores': top_autores,
        'top_categorias': top_categorias,
        'mejores_libros': mejores_libros,
        'total_prestamos': total_prestamos,
        'prestamos_activos': prestamos_activos,
        'prestamos_retrasados': prestamos_retrasados,
    }
    return render(request, 'libros/estadisticas.html', context)
libros/urls.py
from django.urls import path
from . import views

app_name = 'libros'

urlpatterns = [
    path('', views.inicio, name='inicio'),
    path('libros/', views.lista_libros, name='lista_libros'),
    path('libro/<int:id>/', views.detalle_libro, name='detalle_libro'),
    path('autores/', views.lista_autores, name='lista_autores'),
    path('autor/<int:id>/', views.detalle_autor, name='detalle_autor'),
    path('busqueda/', views.busqueda_avanzada, name='busqueda_avanzada'),
    path('estadisticas/', views.estadisticas, name='estadisticas'),
]
biblioteca_project/urls.py
"""
URL configuration for biblioteca_project project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('libros.urls')),
]

# Servir archivos media en desarrollo
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
templates/base/base.html
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Biblioteca Django{% endblock %}</title>
    
    <!-- Bootstrap 5 CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    
    <!-- Font Awesome -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    
    <!-- Custom CSS -->
    {% load static %}
    <link rel="stylesheet" href="{% static 'css/styles.css' %}">
    
    {% block extra_css %}{% endblock %}
</head>
<body>
    <!-- Navbar -->
    <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
        <div class="container">
            <a class="navbar-brand" href="{% url 'libros:inicio' %}">
                <i class="fas fa-book-reader me-2"></i>
                Biblioteca Django
            </a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav ms-auto">
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'libros:inicio' %}">
                            <i class="fas fa-home me-1"></i>Inicio
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'libros:lista_libros' %}">
                            <i class="fas fa-book me-1"></i>Libros
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'libros:lista_autores' %}">
                            <i class="fas fa-user-edit me-1"></i>Autores
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'libros:busqueda_avanzada' %}">
                            <i class="fas fa-search me-1"></i>Búsqueda Avanzada
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'libros:estadisticas' %}">
                            <i class="fas fa-chart-bar me-1"></i>Estadísticas
                        </a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>

    <!-- Main Content -->
    <main class="py-4">
        {% block content %}{% endblock %}
    </main>

    <!-- Footer -->
    <footer class="bg-dark text-white mt-5 py-4">
        <div class="container">
            <div class="row">
                <div class="col-md-4">
                    <h5><i class="fas fa-book-reader me-2"></i>Biblioteca Django</h5>
                    <p class="text-muted">Sistema de gestión bibliotecaria completo desarrollado con Django.</p>
                </div>
                <div class="col-md-4">
                    <h5>Enlaces Rápidos</h5>
                    <ul class="list-unstyled">
                        <li><a href="{% url 'libros:lista_libros' %}" class="text-white-50 text-decoration-none">Catálogo de Libros</a></li>
                        <li><a href="{% url 'libros:lista_autores' %}" class="text-white-50 text-decoration-none">Autores</a></li>
                        <li><a href="{% url 'libros:estadisticas' %}" class="text-white-50 text-decoration-none">Estadísticas</a></li>
                    </ul>
                </div>
                <div class="col-md-4">
                    <h5>Contacto</h5>
                    <p class="text-muted">
                        <i class="fas fa-envelope me-2"></i>biblioteca@example.com<br>
                        <i class="fas fa-phone me-2"></i>+123 456 7890
                    </p>
                </div>
            </div>
            <hr class="bg-secondary">
            <div class="text-center text-muted">
                <p>&copy; 2026 Biblioteca Django. Todos los derechos reservados.</p>
            </div>
        </div>
    </footer>

    <!-- Bootstrap 5 JS -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    
    <!-- Custom JS -->
    <script src="{% static 'js/main.js' %}"></script>
    
    {% block extra_js %}{% endblock %}
</body>
</html>
templates/libros/inicio.html
{% extends 'base/base.html' %}
{% load static %}

{% block title %}Inicio - Biblioteca Django{% endblock %}

{% block content %}
<div class="container">
    <!-- Hero Section -->
    <div class="jumbotron bg-light p-5 rounded-3 mb-4">
        <h1 class="display-4">
            <i class="fas fa-book-reader text-primary"></i> 
            Bienvenido a Biblioteca Django
        </h1>
        <p class="lead">Sistema completo de gestión bibliotecaria con Django</p>
        <hr class="my-4">
        <p>Explora nuestro catálogo de libros, descubre nuevos autores y gestiona préstamos de manera eficiente.</p>
        <a class="btn btn-primary btn-lg" href="{% url 'libros:lista_libros' %}" role="button">
            <i class="fas fa-book me-2"></i>Ver Catálogo
        </a>
    </div>

    <!-- Estadísticas Principales -->
    <div class="row mb-4">
        <div class="col-md-3 mb-3">
            <div class="card text-white bg-primary h-100">
                <div class="card-body">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <h5 class="card-title">Total Libros</h5>
                            <h2 class="mb-0">{{ total_libros }}</h2>
                        </div>
                        <i class="fas fa-book fa-3x opacity-50"></i>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-3 mb-3">
            <div class="card text-white bg-success h-100">
                <div class="card-body">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <h5 class="card-title">Autores</h5>
                            <h2 class="mb-0">{{ total_autores }}</h2>
                        </div>
                        <i class="fas fa-user-edit fa-3x opacity-50"></i>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-3 mb-3">
            <div class="card text-white bg-info h-100">
                <div class="card-body">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <h5 class="card-title">Disponibles</h5>
                            <h2 class="mb-0">{{ libros_disponibles }}</h2>
                        </div>
                        <i class="fas fa-check-circle fa-3x opacity-50"></i>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-3 mb-3">
            <div class="card text-white bg-warning h-100">
                <div class="card-body">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <h5 class="card-title">Préstamos</h5>
                            <h2 class="mb-0">{{ prestamos_activos }}</h2>
                        </div>
                        <i class="fas fa-exchange-alt fa-3x opacity-50"></i>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Libros Destacados -->
    <section class="mb-5">
        <h2 class="mb-4">
            <i class="fas fa-star text-warning"></i> Libros Destacados
        </h2>
        <div class="row">
            {% for libro in libros_destacados %}
            <div class="col-md-4 col-lg-2 mb-4">
                <div class="card h-100 shadow-sm libro-card">
                    {% if libro.portada %}
                    <img src="{{ libro.portada.url }}" class="card-img-top" alt="{{ libro.titulo }}">
                    {% else %}
                    <div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" style="height: 200px;">
                        <i class="fas fa-book fa-3x text-white"></i>
                    </div>
                    {% endif %}
                    <div class="card-body">
                        <h6 class="card-title">{{ libro.titulo|truncatewords:5 }}</h6>
                        <p class="card-text text-muted small">{{ libro.autor.nombre }}</p>
                        <div class="mb-2">
                            <span class="badge bg-warning text-dark">
                                <i class="fas fa-star"></i> {{ libro.calificacion }}
                            </span>
                        </div>
                        <a href="{% url 'libros:detalle_libro' libro.id %}" class="btn btn-sm btn-primary w-100">
                            Ver Detalles
                        </a>
                    </div>
                </div>
            </div>
            {% empty %}
            <p class="text-muted">No hay libros destacados disponibles.</p>
            {% endfor %}
        </div>
    </section>

    <!-- Últimos Libros Agregados -->
    <section>
        <h2 class="mb-4">
            <i class="fas fa-clock text-info"></i> Últimos Libros Agregados
        </h2>
        <div class="row">
            {% for libro in ultimos_libros %}
            <div class="col-md-4 col-lg-2 mb-4">
                <div class="card h-100 shadow-sm libro-card">
                    {% if libro.portada %}
                    <img src="{{ libro.portada.url }}" class="card-img-top" alt="{{ libro.titulo }}">
                    {% else %}
                    <div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" style="height: 200px;">
                        <i class="fas fa-book fa-3x text-white"></i>
                    </div>
                    {% endif %}
                    <div class="card-body">
                        <h6 class="card-title">{{ libro.titulo|truncatewords:5 }}</h6>
                        <p class="card-text text-muted small">{{ libro.autor.nombre }}</p>
                        <div class="mb-2">
                            <span class="badge bg-info">
                                {{ libro.fecha_publicacion|date:"Y" }}
                            </span>
                        </div>
                        <a href="{% url 'libros:detalle_libro' libro.id %}" class="btn btn-sm btn-primary w-100">
                            Ver Detalles
                        </a>
                    </div>
                </div>
            </div>
            {% empty %}
            <p class="text-muted">No hay libros disponibles.</p>
            {% endfor %}
        </div>
    </section>
</div>
{% endblock %}
templates/libros/lista_libros.html
{% extends 'base/base.html' %}
{% load static %}

{% block title %}Catálogo de Libros - Biblioteca Django{% endblock %}

{% block content %}
<div class="container">
    <h1 class="mb-4">
        <i class="fas fa-book text-primary"></i> Catálogo de Libros
    </h1>

    <!-- Barra de Búsqueda y Filtros -->
    <div class="card mb-4">
        <div class="card-body">
            <form method="GET" action="{% url 'libros:lista_libros' %}">
                <div class="row g-3">
                    <div class="col-md-4">
                        <label for="search" class="form-label">Buscar</label>
                        <input type="text" class="form-control" id="search" name="q" 
                               placeholder="Título, ISBN o Autor..." value="{{ busqueda }}">
                    </div>
                    <div class="col-md-3">
                        <label for="categoria" class="form-label">Categoría</label>
                        <select class="form-select" id="categoria" name="categoria">
                            <option value="">Todas las categorías</option>
                            {% for cat in categorias %}
                            <option value="{{ cat.id }}" {% if categoria_seleccionada == cat.id|stringformat:"s" %}selected{% endif %}>
                                {{ cat.nombre }}
                            </option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="col-md-3">
                        <label for="autor" class="form-label">Autor</label>
                        <select class="form-select" id="autor" name="autor">
                            <option value="">Todos los autores</option>
                            {% for autor in autores %}
                            <option value="{{ autor.id }}" {% if autor_seleccionado == autor.id|stringformat:"s" %}selected{% endif %}>
                                {{ autor.nombre }}
                            </option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="col-md-2">
                        <label for="estado" class="form-label">Estado</label>
                        <select class="form-select" id="estado" name="estado">
                            <option value="">Todos</option>
                            {% for estado_value, estado_label in estados %}
                            <option value="{{ estado_value }}" {% if estado_seleccionado == estado_value %}selected{% endif %}>
                                {{ estado_label }}
                            </option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="col-12">
                        <button type="submit" class="btn btn-primary">
                            <i class="fas fa-search"></i> Buscar
                        </button>
                        <a href="{% url 'libros:lista_libros' %}" class="btn btn-secondary">
                            <i class="fas fa-redo"></i> Limpiar
                        </a>
                    </div>
                </div>
            </form>
        </div>
    </div>

    <!-- Resultados -->
    <div class="mb-3">
        <p class="text-muted">
            <i class="fas fa-info-circle"></i> 
            Se encontraron <strong>{{ libros.count }}</strong> libro(s)
        </p>
    </div>

    <div class="row">
        {% for libro in libros %}
        <div class="col-md-6 col-lg-3 mb-4">
            <div class="card h-100 shadow-sm libro-card">
                {% if libro.portada %}
                <img src="{{ libro.portada.url }}" class="card-img-top" alt="{{ libro.titulo }}" style="height: 250px; object-fit: cover;">
                {% else %}
                <div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" style="height: 250px;">
                    <i class="fas fa-book fa-4x text-white"></i>
                </div>
                {% endif %}
                <div class="card-body d-flex flex-column">
                    <h5 class="card-title">{{ libro.titulo|truncatewords:6 }}</h5>
                    <p class="card-text text-muted">
                        <i class="fas fa-user"></i> {{ libro.autor.nombre }}
                    </p>
                    <p class="card-text small">
                        <i class="fas fa-building"></i> {{ libro.editorial.nombre }}
                    </p>
                    
                    <div class="mb-2">
                        {% for categoria in libro.categorias.all|slice:":2" %}
                        <span class="badge bg-secondary">{{ categoria.nombre }}</span>
                        {% endfor %}
                    </div>
                    
                    <div class="mb-2">
                        <span class="badge bg-warning text-dark">
                            <i class="fas fa-star"></i> {{ libro.calificacion }}
                        </span>
                        {% if libro.estado == 'disponible' %}
                        <span class="badge bg-success">Disponible</span>
                        {% elif libro.estado == 'prestado' %}
                        <span class="badge bg-danger">Prestado</span>
                        {% else %}
                        <span class="badge bg-warning">Mantenimiento</span>
                        {% endif %}
                    </div>
                    
                    <div class="mb-2">
                        <strong class="text-primary">${{ libro.precio }}</strong>
                    </div>
                    
                    <div class="mt-auto">
                        <a href="{% url 'libros:detalle_libro' libro.id %}" class="btn btn-primary btn-sm w-100">
                            <i class="fas fa-eye"></i> Ver Detalles
                        </a>
                    </div>
                </div>
            </div>
        </div>
        {% empty %}
        <div class="col-12">
            <div class="alert alert-info">
                <i class="fas fa-info-circle"></i> No se encontraron libros con los criterios especificados.
            </div>
        </div>
        {% endfor %}
    </div>
</div>
{% endblock %}
templates/libros/detalle_libro.html
{% extends 'base/base.html' %}
{% load static %}

{% block title %}{{ libro.titulo }} - Biblioteca Django{% endblock %}

{% block content %}
<div class="container">
    <!-- Breadcrumb -->
    <nav aria-label="breadcrumb">
        <ol class="breadcrumb">
            <li class="breadcrumb-item"><a href="{% url 'libros:inicio' %}">Inicio</a></li>
            <li class="breadcrumb-item"><a href="{% url 'libros:lista_libros' %}">Libros</a></li>
            <li class="breadcrumb-item active">{{ libro.titulo }}</li>
        </ol>
    </nav>

    <div class="row">
        <!-- Portada del Libro -->
        <div class="col-md-4 mb-4">
            <div class="card">
                {% if libro.portada %}
                <img src="{{ libro.portada.url }}" class="card-img-top" alt="{{ libro.titulo }}">
                {% else %}
                <div class="bg-secondary d-flex align-items-center justify-content-center" style="height: 400px;">
                    <i class="fas fa-book fa-5x text-white"></i>
                </div>
                {% endif %}
                <div class="card-body">
                    <h4 class="text-center text-primary">${{ libro.precio }}</h4>
                    <div class="d-grid gap-2">
                        {% if libro.estado == 'disponible' %}
                        <button class="btn btn-success" disabled>
                            <i class="fas fa-check-circle"></i> Disponible
                        </button>
                        {% elif libro.estado == 'prestado' %}
                        <button class="btn btn-danger" disabled>
                            <i class="fas fa-times-circle"></i> Prestado
                        </button>
                        {% else %}
                        <button class="btn btn-warning" disabled>
                            <i class="fas fa-tools"></i> En Mantenimiento
                        </button>
                        {% endif %}
                    </div>
                </div>
            </div>
        </div>

        <!-- Información del Libro -->
        <div class="col-md-8">
            <h1 class="mb-3">{{ libro.titulo }}</h1>
            
            <div class="mb-3">
                <span class="badge bg-warning text-dark fs-6">
                    <i class="fas fa-star"></i> {{ libro.calificacion }} / 5.0
                </span>
                <span class="badge bg-info fs-6">
                    <i class="fas fa-warehouse"></i> Stock: {{ libro.stock }}
                </span>
            </div>

            <div class="card mb-4">
                <div class="card-body">
                    <h5 class="card-title">Información General</h5>
                    <table class="table table-borderless">
                        <tbody>
                            <tr>
                                <th width="30%"><i class="fas fa-user text-primary"></i> Autor:</th>
                                <td>
                                    <a href="{% url 'libros:detalle_autor' libro.autor.id %}">
                                        {{ libro.autor.nombre }}
                                    </a>
                                </td>
                            </tr>
                            <tr>
                                <th><i class="fas fa-building text-primary"></i> Editorial:</th>
                                <td>{{ libro.editorial.nombre }}</td>
                            </tr>
                            <tr>
                                <th><i class="fas fa-barcode text-primary"></i> ISBN:</th>
                                <td>{{ libro.isbn }}</td>
                            </tr>
                            <tr>
                                <th><i class="fas fa-calendar text-primary"></i> Publicación:</th>
                                <td>{{ libro.fecha_publicacion|date:"d/m/Y" }}</td>
                            </tr>
                            <tr>
                                <th><i class="fas fa-file-alt text-primary"></i> Páginas:</th>
                                <td>{{ libro.numero_paginas }} páginas</td>
                            </tr>
                            <tr>
                                <th><i class="fas fa-tags text-primary"></i> Categorías:</th>
                                <td>
                                    {% for categoria in libro.categorias.all %}
                                    <span class="badge bg-secondary">{{ categoria.nombre }}</span>
                                    {% endfor %}
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>

            <div class="card mb-4">
                <div class="card-body">
                    <h5 class="card-title"><i class="fas fa-align-left text-primary"></i> Sinopsis</h5>
                    <p class="card-text">{{ libro.sinopsis }}</p>
                </div>
            </div>
        </div>
    </div>

    <!-- Libros Relacionados -->
    {% if libros_relacionados %}
    <section class="mt-5">
        <h3 class="mb-4">
            <i class="fas fa-book-open text-primary"></i> Libros Relacionados
        </h3>
        <div class="row">
            {% for libro_rel in libros_relacionados %}
            <div class="col-md-3 mb-4">
                <div class="card h-100 shadow-sm libro-card">
                    {% if libro_rel.portada %}
                    <img src="{{ libro_rel.portada.url }}" class="card-img-top" alt="{{ libro_rel.titulo }}" style="height: 200px; object-fit: cover;">
                    {% else %}
                    <div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" style="height: 200px;">
                        <i class="fas fa-book fa-3x text-white"></i>
                    </div>
                    {% endif %}
                    <div class="card-body">
                        <h6 class="card-title">{{ libro_rel.titulo|truncatewords:5 }}</h6>
                        <p class="card-text text-muted small">{{ libro_rel.autor.nombre }}</p>
                        <a href="{% url 'libros:detalle_libro' libro_rel.id %}" class="btn btn-sm btn-primary w-100">
                            Ver Detalles
                        </a>
                    </div>
                </div>
            </div>
            {% endfor %}
        </div>
    </section>
    {% endif %}
</div>
{% endblock %}
templates/libros/lista_autores.html
{% extends 'base/base.html' %}
{% load static %}

{% block title %}Autores - Biblioteca Django{% endblock %}

{% block content %}
<div class="container">
    <h1 class="mb-4">
        <i class="fas fa-user-edit text-primary"></i> Directorio de Autores
    </h1>

    <!-- Barra de Búsqueda -->
    <div class="card mb-4">
        <div class="card-body">
            <form method="GET" action="{% url 'libros:lista_autores' %}">
                <div class="row g-3">
                    <div class="col-md-10">
                        <input type="text" class="form-control" name="q" 
                               placeholder="Buscar autor por nombre o país..." value="{{ busqueda }}">
                    </div>
                    <div class="col-md-2">
                        <button type="submit" class="btn btn-primary w-100">
                            <i class="fas fa-search"></i> Buscar
                        </button>
                    </div>
                </div>
            </form>
        </div>
    </div>

    <!-- Resultados -->
    <div class="mb-3">
        <p class="text-muted">
            <i class="fas fa-info-circle"></i> 
            Total de autores: <strong>{{ autores.count }}</strong>
        </p>
    </div>

    <div class="row">
        {% for autor in autores %}
        <div class="col-md-6 col-lg-4 mb-4">
            <div class="card h-100 shadow-sm autor-card">
                <div class="card-body">
                    <div class="d-flex align-items-start">
                        <div class="flex-shrink-0">
                            {% if autor.foto %}
                            <img src="{{ autor.foto.url }}" class="rounded-circle" 
                                 style="width: 80px; height: 80px; object-fit: cover;" alt="{{ autor.nombre }}">
                            {% else %}
                            <div class="rounded-circle bg-primary d-flex align-items-center justify-content-center"
                                 style="width: 80px; height: 80px;">
                                <i class="fas fa-user fa-2x text-white"></i>
                            </div>
                            {% endif %}
                        </div>
                        <div class="flex-grow-1 ms-3">
                            <h5 class="card-title mb-2">{{ autor.nombre }}</h5>
                            <p class="card-text text-muted mb-2">
                                <i class="fas fa-globe"></i> {{ autor.pais_origen }}
                            </p>
                            <p class="card-text text-muted mb-2">
                                <i class="fas fa-birthday-cake"></i> {{ autor.fecha_nacimiento|date:"d/m/Y" }}
                            </p>
                            <div class="mb-2">
                                <span class="badge bg-primary">
                                    <i class="fas fa-book"></i> {{ autor.total_libros }} libro(s)
                                </span>
                                {% if autor.calificacion_promedio %}
                                <span class="badge bg-warning text-dark">
                                    <i class="fas fa-star"></i> {{ autor.calificacion_promedio|floatformat:1 }}
                                </span>
                                {% endif %}
                            </div>
                            <p class="card-text small">{{ autor.biografia|truncatewords:20 }}</p>
                            <a href="{% url 'libros:detalle_autor' autor.id %}" class="btn btn-primary btn-sm">
                                <i class="fas fa-eye"></i> Ver Perfil
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        {% empty %}
        <div class="col-12">
            <div class="alert alert-info">
                <i class="fas fa-info-circle"></i> No se encontraron autores.
            </div>
        </div>
        {% endfor %}
    </div>
</div>
{% endblock %}
templates/libros/detalle_autor.html
{% extends 'base/base.html' %}
{% load static %}

{% block title %}{{ autor.nombre }} - Biblioteca Django{% endblock %}

{% block content %}
<div class="container">
    <!-- Breadcrumb -->
    <nav aria-label="breadcrumb">
        <ol class="breadcrumb">
            <li class="breadcrumb-item"><a href="{% url 'libros:inicio' %}">Inicio</a></li>
            <li class="breadcrumb-item"><a href="{% url 'libros:lista_autores' %}">Autores</a></li>
            <li class="breadcrumb-item active">{{ autor.nombre }}</li>
        </ol>
    </nav>

    <!-- Perfil del Autor -->
    <div class="row mb-4">
        <div class="col-md-3">
            {% if autor.foto %}
            <img src="{{ autor.foto.url }}" class="img-fluid rounded-circle shadow" alt="{{ autor.nombre }}">
            {% else %}
            <div class="bg-primary rounded-circle d-flex align-items-center justify-content-center mx-auto shadow" 
                 style="width: 200px; height: 200px;">
                <i class="fas fa-user fa-5x text-white"></i>
            </div>
            {% endif %}
        </div>
        <div class="col-md-9">
            <h1 class="mb-3">{{ autor.nombre }}</h1>
            
            <div class="card mb-3">
                <div class="card-body">
                    <h5 class="card-title">Información Personal</h5>
                    <table class="table table-borderless mb-0">
                        <tbody>
                            <tr>
                                <th width="30%"><i class="fas fa-birthday-cake text-primary"></i> Fecha de Nacimiento:</th>
                                <td>{{ autor.fecha_nacimiento|date:"d/m/Y" }}</td>
                            </tr>
                            <tr>
                                <th><i class="fas fa-globe text-primary"></i> País de Origen:</th>
                                <td>{{ autor.pais_origen }}</td>
                            </tr>
                            <tr>
                                <th><i class="fas fa-book text-primary"></i> Total de Libros:</th>
                                <td><span class="badge bg-primary">{{ total_libros }}</span></td>
                            </tr>
                            <tr>
                                <th><i class="fas fa-star text-primary"></i> Calificación Promedio:</th>
                                <td>
                                    <span class="badge bg-warning text-dark">{{ calificacion_promedio }} / 5.0</span>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>

            <div class="card">
                <div class="card-body">
                    <h5 class="card-title"><i class="fas fa-align-left text-primary"></i> Biografía</h5>
                    <p class="card-text">{{ autor.biografia }}</p>
                </div>
            </div>
        </div>
    </div>

    <!-- Libros del Autor -->
    <section class="mt-5">
        <h3 class="mb-4">
            <i class="fas fa-book-open text-primary"></i> Obras de {{ autor.nombre }}
        </h3>
        
        {% if libros %}
        <div class="row">
            {% for libro in libros %}
            <div class="col-md-6 col-lg-3 mb-4">
                <div class="card h-100 shadow-sm libro-card">
                    {% if libro.portada %}
                    <img src="{{ libro.portada.url }}" class="card-img-top" alt="{{ libro.titulo }}" 
                         style="height: 250px; object-fit: cover;">
                    {% else %}
                    <div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" 
                         style="height: 250px;">
                        <i class="fas fa-book fa-4x text-white"></i>
                    </div>
                    {% endif %}
                    <div class="card-body d-flex flex-column">
                        <h5 class="card-title">{{ libro.titulo|truncatewords:6 }}</h5>
                        <p class="card-text text-muted small">
                            <i class="fas fa-calendar"></i> {{ libro.fecha_publicacion|date:"Y" }}
                        </p>
                        
                        <div class="mb-2">
                            {% for categoria in libro.categorias.all|slice:":2" %}
                            <span class="badge bg-secondary">{{ categoria.nombre }}</span>
                            {% endfor %}
                        </div>
                        
                        <div class="mb-2">
                            <span class="badge bg-warning text-dark">
                                <i class="fas fa-star"></i> {{ libro.calificacion }}
                            </span>
                            {% if libro.estado == 'disponible' %}
                            <span class="badge bg-success">Disponible</span>
                            {% elif libro.estado == 'prestado' %}
                            <span class="badge bg-danger">Prestado</span>
                            {% else %}
                            <span class="badge bg-warning">Mantenimiento</span>
                            {% endif %}
                        </div>
                        
                        <div class="mb-2">
                            <strong class="text-primary">${{ libro.precio }}</strong>
                        </div>
                        
                        <div class="mt-auto">
                            <a href="{% url 'libros:detalle_libro' libro.id %}" class="btn btn-primary btn-sm w-100">
                                <i class="fas fa-eye"></i> Ver Detalles
                            </a>
                        </div>
                    </div>
                </div>
            </div>
            {% endfor %}
        </div>
        {% else %}
        <div class="alert alert-info">
            <i class="fas fa-info-circle"></i> Este autor aún no tiene libros registrados en la biblioteca.
        </div>
        {% endif %}
    </section>
</div>
{% endblock %}
templates/libros/busqueda_avanzada.html
{% extends 'base/base.html' %}
{% load static %}

{% block title %}Búsqueda Avanzada - Biblioteca Django{% endblock %}

{% block content %}
<div class="container">
    <h1 class="mb-4">
        <i class="fas fa-search text-primary"></i> Búsqueda Avanzada
    </h1>

    <!-- Formulario de Búsqueda Avanzada -->
    <div class="card mb-4">
        <div class="card-header bg-primary text-white">
            <h5 class="mb-0"><i class="fas fa-filter"></i> Filtros de Búsqueda</h5>
        </div>
        <div class="card-body">
            <form method="GET" action="{% url 'libros:busqueda_avanzada' %}">
                <div class="row g-3">
                    <!-- Título -->
                    <div class="col-md-6">
                        <label for="titulo" class="form-label">Título</label>
                        <input type="text" class="form-control" id="titulo" name="titulo" 
                               placeholder="Buscar por título..." value="{{ filtros.titulo }}">
                    </div>

                    <!-- Autor -->
                    <div class="col-md-6">
                        <label for="autor" class="form-label">Autor</label>
                        <input type="text" class="form-control" id="autor" name="autor" 
                               placeholder="Nombre del autor..." value="{{ filtros.autor }}">
                    </div>

                    <!-- Categoría -->
                    <div class="col-md-4">
                        <label for="categoria" class="form-label">Categoría</label>
                        <select class="form-select" id="categoria" name="categoria">
                            <option value="">Todas las categorías</option>
                            {% for cat in categorias %}
                            <option value="{{ cat.id }}" {% if filtros.categoria == cat.id|stringformat:"s" %}selected{% endif %}>
                                {{ cat.nombre }}
                            </option>
                            {% endfor %}
                        </select>
                    </div>

                    <!-- Editorial -->
                    <div class="col-md-4">
                        <label for="editorial" class="form-label">Editorial</label>
                        <select class="form-select" id="editorial" name="editorial">
                            <option value="">Todas las editoriales</option>
                            {% for edit in editoriales %}
                            <option value="{{ edit.id }}" {% if filtros.editorial == edit.id|stringformat:"s" %}selected{% endif %}>
                                {{ edit.nombre }}
                            </option>
                            {% endfor %}
                        </select>
                    </div>

                    <!-- Calificación Mínima -->
                    <div class="col-md-4">
                        <label for="calificacion_min" class="form-label">Calificación Mínima</label>
                        <select class="form-select" id="calificacion_min" name="calificacion_min">
                            <option value="">Todas</option>
                            <option value="5.0" {% if filtros.calificacion_min == "5.0" %}selected{% endif %}>5 Estrellas</option>
                            <option value="4.0" {% if filtros.calificacion_min == "4.0" %}selected{% endif %}>4+ Estrellas</option>
                            <option value="3.0" {% if filtros.calificacion_min == "3.0" %}selected{% endif %}>3+ Estrellas</option>
                            <option value="2.0" {% if filtros.calificacion_min == "2.0" %}selected{% endif %}>2+ Estrellas</option>
                        </select>
                    </div>

                    <!-- Año Desde -->
                    <div class="col-md-3">
                        <label for="año_desde" class="form-label">Año Desde</label>
                        <input type="number" class="form-control" id="año_desde" name="año_desde" 
                               placeholder="2000" min="1900" max="2026" value="{{ filtros.año_desde }}">
                    </div>

                    <!-- Año Hasta -->
                    <div class="col-md-3">
                        <label for="año_hasta" class="form-label">Año Hasta</label>
                        <input type="number" class="form-control" id="año_hasta" name="año_hasta" 
                               placeholder="2026" min="1900" max="2026" value="{{ filtros.año_hasta }}">
                    </div>

                    <!-- Precio Mínimo -->
                    <div class="col-md-3">
                        <label for="precio_min" class="form-label">Precio Mínimo ($)</label>
                        <input type="number" class="form-control" id="precio_min" name="precio_min" 
                               placeholder="0" step="0.01" min="0" value="{{ filtros.precio_min }}">
                    </div>

                    <!-- Precio Máximo -->
                    <div class="col-md-3">
                        <label for="precio_max" class="form-label">Precio Máximo ($)</label>
                        <input type="number" class="form-control" id="precio_max" name="precio_max" 
                               placeholder="1000" step="0.01" min="0" value="{{ filtros.precio_max }}">
                    </div>

                    <!-- Botones -->
                    <div class="col-12">
                        <button type="submit" class="btn btn-primary">
                            <i class="fas fa-search"></i> Buscar
                        </button>
                        <a href="{% url 'libros:busqueda_avanzada' %}" class="btn btn-secondary">
                            <i class="fas fa-redo"></i> Limpiar Filtros
                        </a>
                    </div>
                </div>
            </form>
        </div>
    </div>

    <!-- Resultados -->
    <div class="mb-3">
        <h4>
            <i class="fas fa-list"></i> Resultados de la Búsqueda
            <span class="badge bg-primary">{{ libros.count }} libro(s)</span>
        </h4>
    </div>

    <div class="row">
        {% for libro in libros %}
        <div class="col-md-6 col-lg-3 mb-4">
            <div class="card h-100 shadow-sm libro-card">
                {% if libro.portada %}
                <img src="{{ libro.portada.url }}" class="card-img-top" alt="{{ libro.titulo }}" 
                     style="height: 250px; object-fit: cover;">
                {% else %}
                <div class="card-img-top bg-secondary d-flex align-items-center justify-content-center" 
                     style="height: 250px;">
                    <i class="fas fa-book fa-4x text-white"></i>
                </div>
                {% endif %}
                <div class="card-body d-flex flex-column">
                    <h5 class="card-title">{{ libro.titulo|truncatewords:6 }}</h5>
                    <p class="card-text text-muted">
                        <i class="fas fa-user"></i> {{ libro.autor.nombre }}
                    </p>
                    <p class="card-text small">
                        <i class="fas fa-calendar"></i> {{ libro.fecha_publicacion|date:"Y" }}
                    </p>
                    
                    <div class="mb-2">
                        <span class="badge bg-warning text-dark">
                            <i class="fas fa-star"></i> {{ libro.calificacion }}
                        </span>
                    </div>
                    
                    <div class="mb-2">
                        <strong class="text-primary">${{ libro.precio }}</strong>
                    </div>
                    
                    <div class="mt-auto">
                        <a href="{% url 'libros:detalle_libro' libro.id %}" class="btn btn-primary btn-sm w-100">
                            <i class="fas fa-eye"></i> Ver Detalles
                        </a>
                    </div>
                </div>
            </div>
        </div>
        {% empty %}
        <div class="col-12">
            <div class="alert alert-info">
                <i class="fas fa-info-circle"></i> No se encontraron libros con los criterios especificados. 
                Intenta ajustar los filtros de búsqueda.
            </div>
        </div>
        {% endfor %}
    </div>
</div>
{% endblock %}
templates/libros/estadisticas.html
{% extends 'base/base.html' %}
{% load static %}

{% block title %}Estadísticas - Biblioteca Django{% endblock %}

{% block content %}
<div class="container">
    <h1 class="mb-4">
        <i class="fas fa-chart-bar text-primary"></i> Dashboard de Estadísticas
    </h1>

    <!-- Estadísticas Generales -->
    <div class="row mb-4">
        <div class="col-md-3 mb-3">
            <div class="card text-white bg-primary h-100">
                <div class="card-body">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <h6 class="card-title">Total Libros</h6>
                            <h2 class="mb-0">{{ total_libros }}</h2>
                        </div>
                        <i class="fas fa-book fa-3x opacity-50"></i>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-3 mb-3">
            <div class="card text-white bg-success h-100">
                <div class="card-body">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <h6 class="card-title">Autores</h6>
                            <h2 class="mb-0">{{ total_autores }}</h2>
                        </div>
                        <i class="fas fa-user-edit fa-3x opacity-50"></i>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-3 mb-3">
            <div class="card text-white bg-info h-100">
                <div class="card-body">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <h6 class="card-title">Categorías</h6>
                            <h2 class="mb-0">{{ total_categorias }}</h2>
                        </div>
                        <i class="fas fa-tags fa-3x opacity-50"></i>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-3 mb-3">
            <div class="card text-white bg-warning h-100">
                <div class="card-body">
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <h6 class="card-title">Editoriales</h6>
                            <h2 class="mb-0">{{ total_editoriales }}</h2>
                        </div>
                        <i class="fas fa-building fa-3x opacity-50"></i>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Libros por Estado -->
    <div class="row mb-4">
        <div class="col-md-6">
            <div class="card">
                <div class="card-header bg-primary text-white">
                    <h5 class="mb-0"><i class="fas fa-chart-pie"></i> Libros por Estado</h5>
                </div>
                <div class="card-body">
                    <table class="table table-hover">
                        <thead>
                            <tr>
                                <th>Estado</th>
                                <th>Cantidad</th>
                                <th>Porcentaje</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for item in libros_por_estado %}
                            <tr>
                                <td>
                                    {% if item.estado == 'disponible' %}
                                    <span class="badge bg-success">Disponible</span>
                                    {% elif item.estado == 'prestado' %}
                                    <span class="badge bg-danger">Prestado</span>
                                    {% else %}
                                    <span class="badge bg-warning">Mantenimiento</span>
                                    {% endif %}
                                </td>
                                <td><strong>{{ item.total }}</strong></td>
                                <td>
                                    {% widthratio item.total total_libros 100 %}%
                                </td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

        <!-- Estadísticas de Préstamos -->
        <div class="col-md-6">
            <div class="card">
                <div class="card-header bg-success text-white">
                    <h5 class="mb-0"><i class="fas fa-exchange-alt"></i> Estadísticas de Préstamos</h5>
                </div>
                <div class="card-body">
                    <table class="table table-hover">
                        <tbody>
                            <tr>
                                <th>Total Préstamos</th>
                                <td><span class="badge bg-primary fs-5">{{ total_prestamos }}</span></td>
                            </tr>
                            <tr>
                                <th>Préstamos Activos</th>
                                <td><span class="badge bg-success fs-5">{{ prestamos_activos }}</span></td>
                            </tr>
                            <tr>
                                <th>Préstamos Retrasados</th>
                                <td><span class="badge bg-danger fs-5">{{ prestamos_retrasados }}</span></td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>

    <!-- Top 10 Autores -->
    <div class="row mb-4">
        <div class="col-md-6">
            <div class="card">
                <div class="card-header bg-info text-white">
                    <h5 class="mb-0"><i class="fas fa-trophy"></i> Top 10 Autores (por cantidad de libros)</h5>
                </div>
                <div class="card-body">
                    <table class="table table-striped table-hover">
                        <thead>
                            <tr>
                                <th>#</th>
                                <th>Autor</th>
                                <th>Libros</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for autor in top_autores %}
                            <tr>
                                <td>{{ forloop.counter }}</td>
                                <td>
                                    <a href="{% url 'libros:detalle_autor' autor.id %}">
                                        {{ autor.nombre }}
                                    </a>
                                </td>
                                <td><span class="badge bg-primary">{{ autor.total_libros }}</span></td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

        <!-- Top 10 Categorías -->
        <div class="col-md-6">
            <div class="card">
                <div class="card-header bg-warning text-dark">
                    <h5 class="mb-0"><i class="fas fa-star"></i> Top 10 Categorías Más Populares</h5>
                </div>
                <div class="card-body">
                    <table class="table table-striped table-hover">
                        <thead>
                            <tr>
                                <th>#</th>
                                <th>Categoría</th>
                                <th>Libros</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for categoria in top_categorias %}
                            <tr>
                                <td>{{ forloop.counter }}</td>
                                <td>{{ categoria.nombre }}</td>
                                <td><span class="badge bg-warning text-dark">{{ categoria.total_libros }}</span></td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>

    <!-- Libros Mejor Calificados -->
    <div class="row">
        <div class="col-12">
            <div class="card">
                <div class="card-header bg-danger text-white">
                    <h5 class="mb-0"><i class="fas fa-star"></i> Top 10 Libros Mejor Calificados</h5>
                </div>
                <div class="card-body">
                    <div class="table-responsive">
                        <table class="table table-striped table-hover">
                            <thead>
                                <tr>
                                    <th>#</th>
                                    <th>Título</th>
                                    <th>Autor</th>
                                    <th>Editorial</th>
                                    <th>Calificación</th>
                                    <th>Estado</th>
                                    <th>Acciones</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for libro in mejores_libros %}
                                <tr>
                                    <td>{{ forloop.counter }}</td>
                                    <td>{{ libro.titulo }}</td>
                                    <td>
                                        <a href="{% url 'libros:detalle_autor' libro.autor.id %}">
                                            {{ libro.autor.nombre }}
                                        </a>
                                    </td>
                                    <td>{{ libro.editorial.nombre }}</td>
                                    <td>
                                        <span class="badge bg-warning text-dark">
                                            <i class="fas fa-star"></i> {{ libro.calificacion }}
                                        </span>
                                    </td>
                                    <td>
                                        {% if libro.estado == 'disponible' %}
                                        <span class="badge bg-success">Disponible</span>
                                        {% elif libro.estado == 'prestado' %}
                                        <span class="badge bg-danger">Prestado</span>
                                        {% else %}
                                        <span class="badge bg-warning">Mantenimiento</span>
                                        {% endif %}
                                    </td>
                                    <td>
                                        <a href="{% url 'libros:detalle_libro' libro.id %}" class="btn btn-sm btn-primary">
                                            <i class="fas fa-eye"></i> Ver
                                        </a>
                                    </td>
                                </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}
static/css/styles.css (284 líneas)
/* ===================================
   BIBLIOTECA DJANGO - ESTILOS PERSONALIZADOS
   =================================== */

:root {
    --primary-color: #0d6efd;
    --secondary-color: #6c757d;
    --success-color: #198754;
    --info-color: #0dcaf0;
    --warning-color: #ffc107;
    --danger-color: #dc3545;
    --dark-color: #212529;
    --light-color: #f8f9fa;
}

/* General */
body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-color: #f5f5f5;
}

/* Navbar */
.navbar-brand {
    font-weight: bold;
    font-size: 1.5rem;
    transition: all 0.3s ease;
}

.navbar-brand:hover {
    transform: scale(1.05);
}

.nav-link {
    transition: all 0.3s ease;
    position: relative;
}

.nav-link::after {
    content: '';
    position: absolute;
    width: 0;
    height: 2px;
    bottom: 0;
    left: 50%;
    background-color: white;
    transition: all 0.3s ease;
    transform: translateX(-50%);
}

.nav-link:hover::after {
    width: 80%;
}

/* Cards */
.card {
    border: none;
    border-radius: 10px;
    transition: all 0.3s ease;
}

.card:hover {
    transform: translateY(-5px);
    box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}

/* Libro Cards */
.libro-card {
    transition: all 0.3s ease;
    overflow: hidden;
}

.libro-card:hover {
    transform: translateY(-10px);
    box-shadow: 0 15px 30px rgba(0,0,0,0.2);
}

.libro-card img {
    transition: all 0.3s ease;
}

.libro-card:hover img {
    transform: scale(1.1);
}

/* Autor Cards */
.autor-card {
    transition: all 0.3s ease;
}

.autor-card:hover {
    transform: translateY(-5px);
    box-shadow: 0 10px 20px rgba(0,0,0,0.15);
}

/* Jumbotron */
.jumbotron {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}

.jumbotron h1 {
    text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
}

/* Buttons */
.btn {
    border-radius: 5px;
    transition: all 0.3s ease;
    font-weight: 500;
}

.btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}

/* Badges */
.badge {
    padding: 0.5em 0.8em;
    font-weight: 500;
}

/* Tables */
.table {
    background-color: white;
}

.table-hover tbody tr {
    transition: all 0.3s ease;
}

.table-hover tbody tr:hover {
    background-color: rgba(13, 110, 253, 0.05);
    transform: scale(1.01);
}

/* Forms */
.form-control, .form-select {
    border-radius: 5px;
    border: 1px solid #dee2e6;
    transition: all 0.3s ease;
}

.form-control:focus, .form-select:focus {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
}

/* Footer */
footer {
    margin-top: auto;
}

footer a:hover {
    color: white !important;
    transition: color 0.3s ease;
}

/* Animations */
@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.fade-in {
    animation: fadeIn 0.5s ease;
}

/* Loading Spinner */
.spinner-border {
    width: 3rem;
    height: 3rem;
}

/* Breadcrumb */
.breadcrumb {
    background-color: transparent;
    padding: 0.75rem 0;
}

.breadcrumb-item a {
    color: var(--primary-color);
    text-decoration: none;
}

.breadcrumb-item a:hover {
    text-decoration: underline;
}

/* Rounded Images */
img.rounded-circle {
    object-fit: cover;
}

/* Custom Scrollbar */
::-webkit-scrollbar {
    width: 10px;
}

::-webkit-scrollbar-track {
    background: #f1f1f1;
}

::-webkit-scrollbar-thumb {
    background: var(--primary-color);
    border-radius: 5px;
}

::-webkit-scrollbar-thumb:hover {
    background: #0b5ed7;
}

/* Responsive adjustments */
@media (max-width: 768px) {
    .jumbotron h1 {
        font-size: 2rem;
    }
    
    .navbar-brand {
        font-size: 1.2rem;
    }
}

/* Opacity utilities */
.opacity-50 {
    opacity: 0.5;
}

/* Card header custom */
.card-header {
    border-bottom: 3px solid rgba(0,0,0,0.1);
    font-weight: bold;
}

/* Image placeholders */
.card-img-top {
    background-color: #e9ecef;
}

/* Text utilities */
.text-muted {
    color: #6c757d !important;
}

/* Shadow utilities */
.shadow-sm {
    box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important;
}

.shadow {
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
}

/* Success alert */
.alert {
    border-radius: 10px;
    border: none;
}

/* Custom spacing */
.mb-custom {
    margin-bottom: 2rem;
}

.mt-custom {
    margin-top: 2rem;
}

/* Stats cards animation */
.card.text-white {
    transition: all 0.3s ease;
}

.card.text-white:hover {
    transform: scale(1.05);
}
static/js/main.js (238 líneas)
// ===================================
// BIBLIOTECA DJANGO - JAVASCRIPT PERSONALIZADO
// ===================================

// Esperar a que el DOM esté completamente cargado
document.addEventListener('DOMContentLoaded', function() {
    
    // Inicializar tooltips de Bootstrap
    var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
    var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
        return new bootstrap.Tooltip(tooltipTriggerEl);
    });

    // Inicializar popovers de Bootstrap
    var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
    var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
        return new bootstrap.Popover(popoverTriggerEl);
    });

    // Añadir animación de fade-in a las tarjetas
    const cards = document.querySelectorAll('.card');
    cards.forEach((card, index) => {
        card.style.animation = `fadeIn 0.5s ease ${index * 0.1}s both`;
    });

    // Confirmación antes de eliminar (si se implementa)
    const deleteButtons = document.querySelectorAll('.btn-delete');
    deleteButtons.forEach(button => {
        button.addEventListener('click', function(e) {
            if (!confirm('¿Estás seguro de que deseas eliminar este elemento?')) {
                e.preventDefault();
            }
        });
    });

    // Búsqueda en tiempo real (opcional)
    const searchInput = document.querySelector('#search');
    if (searchInput) {
        let searchTimeout;
        searchInput.addEventListener('input', function() {
            clearTimeout(searchTimeout);
            searchTimeout = setTimeout(() => {
                // Aquí se podría implementar búsqueda AJAX
                console.log('Buscando:', this.value);
            }, 500);
        });
    }

    // Validación de formularios
    const forms = document.querySelectorAll('.needs-validation');
    Array.from(forms).forEach(form => {
        form.addEventListener('submit', event => {
            if (!form.checkValidity()) {
                event.preventDefault();
                event.stopPropagation();
            }
            form.classList.add('was-validated');
        }, false);
    });

    // Scroll suave para enlaces internos
    document.querySelectorAll('a[href^="#"]').forEach(anchor => {
        anchor.addEventListener('click', function (e) {
            const target = document.querySelector(this.getAttribute('href'));
            if (target) {
                e.preventDefault();
                target.scrollIntoView({
                    behavior: 'smooth',
                    block: 'start'
                });
            }
        });
    });

    // Botón de volver arriba
    const backToTopButton = createBackToTopButton();
    document.body.appendChild(backToTopButton);
    
    window.addEventListener('scroll', () => {
        if (window.pageYOffset > 300) {
            backToTopButton.style.display = 'block';
        } else {
            backToTopButton.style.display = 'none';
        }
    });

    backToTopButton.addEventListener('click', () => {
        window.scrollTo({
            top: 0,
            behavior: 'smooth'
        });
    });

    // Contador animado para estadísticas
    animateCounters();

    // Lazy loading para imágenes
    if ('IntersectionObserver' in window) {
        const imageObserver = new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const img = entry.target;
                    img.src = img.dataset.src;
                    img.classList.remove('lazy');
                    imageObserver.unobserve(img);
                }
            });
        });

        document.querySelectorAll('img.lazy').forEach(img => {
            imageObserver.observe(img);
        });
    }

    // Highlight active nav link
    highlightActiveNavLink();
});

// Función para crear botón de volver arriba
function createBackToTopButton() {
    const button = document.createElement('button');
    button.innerHTML = '<i class="fas fa-arrow-up"></i>';
    button.className = 'btn btn-primary';
    button.style.cssText = `
        position: fixed;
        bottom: 30px;
        right: 30px;
        display: none;
        z-index: 1000;
        border-radius: 50%;
        width: 50px;
        height: 50px;
        box-shadow: 0 5px 15px rgba(0,0,0,0.3);
    `;
    button.setAttribute('title', 'Volver arriba');
    return button;
}

// Función para animar contadores
function animateCounters() {
    const counters = document.querySelectorAll('.card-body h2');
    const speed = 200;

    counters.forEach(counter => {
        const updateCount = () => {
            const target = +counter.innerText;
            const count = +counter.getAttribute('data-count') || 0;
            const increment = target / speed;

            if (count < target) {
                counter.setAttribute('data-count', Math.ceil(count + increment));
                counter.innerText = Math.ceil(count + increment);
                setTimeout(updateCount, 1);
            } else {
                counter.innerText = target;
            }
        };

        // Solo animar si es un número
        if (!isNaN(counter.innerText)) {
            const originalValue = counter.innerText;
            counter.innerText = '0';
            counter.setAttribute('data-count', '0');
            
            // Usar Intersection Observer para animar cuando sea visible
            const observer = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        counter.innerText = originalValue;
                        observer.unobserve(counter);
                    }
                });
            });
            
            observer.observe(counter);
        }
    });
}

// Función para resaltar el enlace activo en la navegación
function highlightActiveNavLink() {
    const currentPath = window.location.pathname;
    const navLinks = document.querySelectorAll('.navbar-nav .nav-link');
    
    navLinks.forEach(link => {
        if (link.getAttribute('href') === currentPath) {
            link.classList.add('active');
        } else {
            link.classList.remove('active');
        }
    });
}

// Función de utilidad para mostrar mensajes toast
function showToast(message, type = 'info') {
    const toastHTML = `
        <div class="toast align-items-center text-white bg-${type} border-0" role="alert" aria-live="assertive" aria-atomic="true">
            <div class="d-flex">
                <div class="toast-body">
                    ${message}
                </div>
                <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
            </div>
        </div>
    `;
    
    // Crear contenedor de toasts si no existe
    let toastContainer = document.querySelector('.toast-container');
    if (!toastContainer) {
        toastContainer = document.createElement('div');
        toastContainer.className = 'toast-container position-fixed bottom-0 end-0 p-3';
        document.body.appendChild(toastContainer);
    }
    
    toastContainer.insertAdjacentHTML('beforeend', toastHTML);
    const toastElement = toastContainer.lastElementChild;
    const toast = new bootstrap.Toast(toastElement);
    toast.show();
    
    // Eliminar el toast después de que se oculte
    toastElement.addEventListener('hidden.bs.toast', () => {
        toastElement.remove();
    });
}

// Función para formatear números con separadores de miles
function formatNumber(num) {
    return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

// Exportar funciones para uso global
window.bibliotecaApp = {
    showToast,
    formatNumber
};

console.log('Biblioteca Django - Sistema cargado correctamente ✓');
biblioteca_project/settings.py (Actualizaciones)
# Actualizar TEMPLATES (línea ~60):
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],  # <--- AGREGAR ESTA LÍNEA
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# Actualizar STATIC y MEDIA (al final del archivo):
STATIC_URL = 'static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
STATIC_ROOT = BASE_DIR / 'staticfiles'

MEDIA_URL = 'media/'
MEDIA_ROOT = BASE_DIR / 'media'
INSTRUCCIONES DE EJECUCIÓN
Paso a paso:
  1. Activar entorno virtual:
    .\venv\Scripts\activate
  2. Ejecutar migraciones:
    python manage.py makemigrations
    python manage.py migrate
  3. Crear superusuario:
    python manage.py createsuperuser
  4. Ejecutar servidor:
    python manage.py runserver
  5. Visitar: http://127.0.0.1:8000/
URLs Disponibles:
  • / - Página principal
  • /libros/ - Catálogo
  • /libro/<id>/ - Detalle libro
  • /autores/ - Autores
  • /autor/<id>/ - Detalle autor
  • /busqueda/ - Búsqueda avanzada
  • /estadisticas/ - Dashboard
  • /admin/ - Panel admin