CreaRack-SL

Campo Blueprint.sort_order (orden manual de secciones)

Descripción

Blueprint.sort_order es un nuevo campo en el modelo Blueprint (v1.50.0) que almacena el orden manual de las secciones del Dashboard (Maps y Filas).

Permite que cada organización tenga un orden personalizado y persistente del listado de maps/rows, en lugar del anterior orden fijo alfabético.

Definición

# blueprints/models.py

class Blueprint(models.Model):
    # ... campos existentes ...
    
    # Orden manual de las secciones del Dashboard (drag&drop, por organización).
    # NULL = sin ordenar todavía → va al final; el siguiente reorder lo fija.
    sort_order = models.IntegerField(null=True, blank=True)

Características

AspectoValor
TipoIntegerField
NullableSí (null=True, blank=True)
DefaultNone (NULL en BD)
ScopePor organization (FK)
ÍndiceNo (acceso por filtro + sort, no búsqueda high-volume)
Soft-deleteRespeta deleted_at (migración filtra activos)

Semántica

  • sort_order = 0..N: posición explícita asignada por drag&drop (POST /api/blueprints/reorder).
  • sort_order = NULL: blueprints sin ordenar aún (nuevos o nunca reordenados).
    • Aparecen al final en el listado.
    • Entre ellos, se ordenan alfabéticamente por name.
    • El primer reorder que los incluya les asigna índice definitivo.
  • Orden final en vista: (no_map, sin_ordenar, sort_order, nombre, rack).

Migración

Archivo: blueprints/migrations/0010_blueprint_sort_order.py (v1.50.0)

def backfill_sort_order(apps, schema_editor):
    Blueprint = apps.get_model("blueprints", "Blueprint")
    org_ids = Blueprint.objects.values_list("organization_id", flat=True).distinct()
    for org_id in org_ids:
        bps = list(Blueprint.objects
            .filter(organization_id=org_id, deleted_at__isnull=True)
            .order_by("name"))
        for idx, bp in enumerate(bps):
            bp.sort_order = idx
        Blueprint.objects.bulk_update(bps, ["sort_order"])

Backfill:

  • Por cada organización, ordena blueprints activos (no borrados) alfabéticamente por name.
  • Asigna sort_order = 0..N-1 según ese orden.
  • Objetivo: deploy sin cambios visuales (preservar orden anterior).

Migración reversible: RunPython con noop (no deshacer el backfill, pero reverting el campo es seguro).

Caso de uso: Drag&Drop

# Frontend: usuario arrastra "Beta" al inicio
POST /api/blueprints/reorder
{
  "blueprint_ids": [2, 1, 3]  # Beta(2), Alpha(1), Gamma(3)
}

# Backend: asigna
Blueprint(id=2).sort_order = 0  # Beta → inicio
Blueprint(id=1).sort_order = 1  # Alpha
Blueprint(id=3).sort_order = 2  # Gamma

Siguiente render: racks_list() en core/htmx_views.py ordena por esta clave:

key=lambda r: (
    r.blueprint_name == "",      # "No Map" al final
    r.blueprint_sort is None,    # sin ordenar después
    r.blueprint_sort,            # orden manual
    r.blueprint_name.lower(),    # alfabético entre los sin ordenar
    r.name.lower()               # nombre del rack
)

Resultado: Beta → Alpha → Gamma en el Dashboard.

Acceso en vistas

Dos puntos de acceso aplican sort_order:

1. racks/views.py — First render (GET /)

def index(request):
    # ... build racks_list ...
    
    for rack in racks_list:
        rack.blueprint_sort = first_placement.blueprint.sort_order if first_placement else None
    
    racks = sorted(racks_list, key=lambda r: (
        r.blueprint_name == "",
        r.blueprint_sort is None,
        r.blueprint_sort if r.blueprint_sort is not None else 0,
        r.blueprint_name.lower(),
        r.name.lower()
    ))

2. core/htmx_views.py — Refresh HTMX (partial)

def racks_list(request):
    # ... build racks_list ...
    
    for rack in racks_list:
        rack.blueprint_sort = first_placement.blueprint.sort_order if first_placement else None
    
    racks = sorted(racks_list, key=lambda r: (
        r.blueprint_name == "",
        r.blueprint_sort is None,
        r.blueprint_sort if r.blueprint_sort is not None else 0,
        r.blueprint_name.lower(),
        r.name.lower()
    ))

Nota: ambas usan la misma clave de sort, requisito de {% regroup %} en template.

Performance

  • Lectura: sort_order es un int → comparación rápida.
  • Escritura: bulk_update() en una sola query por reorder (típicamente 3-20 blueprints).
  • Índice: no necesario (acceso siempre filtrado + sort, no búsqueda de igualdad).

Ejemplos de orden resultante

Organización Datacenter-A:

1. [sort_order=0] Maps → Alpha         ← usuario lo arrastró primero
2. [sort_order=1] Maps → Gamma         ← usuario lo arrastró segundo
3. [sort_order=NULL] Maps → Zeta       ← nuevo, aún sin ordenar (alfabético)
4. [sort_order=2] Filas → Fila-1       ← usuario lo arrastró tercero
5. Rooms                                ← fijo
6. No Map                               ← fijo, siempre al final

Véase también

  • [[feature—dashboard—reorder-sections-dragdrop]]
  • [[entity—blueprints—endpoint—reorder]]
  • [[entity—blueprints—model—blueprint]]
  • [[entity—core—model—organization]]