CreaRack-SL

Schema: PlacementInputSchema — parámetros de creación/actualización de placements

Identificación

Módulo: blueprints/api/schemas.py
Clase: PlacementInputSchema
Frameworkw: Ninja (Django REST framework compatible)
Versión introducida: v1.0.0
Última modificación: v1.48.0 (2026-07-10)

Descripción

Schema (Data Transfer Object) que valida y serializa los parámetros de entrada para operaciones sobre BlueprintPlacement (colocación de objetos en el mapa). Se usa en endpoints como:

  • POST /api/blueprints/{bp_id}/rack — crear un rack real
  • POST /api/blueprints/{bp_id}/placements — crear un placement genérico
  • PUT /api/blueprints/{bp_id}/placements/{rack_id} — actualizar un placement

Estructura

class PlacementInputSchema(Schema):
    x: float                   # Coordenada X en el canvas
    y: float                   # Coordenada Y en el canvas
    rotation: int | None = 0   # Rotación en grados (0–360). Default: 0
    style_props: str | None = "{}"
                               # JSON string con propiedades visuales (color, tamaño, etc.)
                               # Ej: '{"color": "#ff9900", "width": 120, "height": 35}'
    
    # v1.48.0 (NEW)
    name: str | None = None    # Nombre inicial del objeto (para racks) o etiqueta
                               # Máx 100 caracteres tras limpieza
                               # Si se omite: default depende del endpoint

Campos

x: float (requerido)

  • Tipo: número flotante
  • Rango: típicamente 0–10000 (tamaño del canvas)
  • Significado: posición horizontal en píxeles del mapa
  • Validación: ninguna especial (frontend valida el snapToGrid)

y: float (requerido)

  • Tipo: número flotante
  • Rango: típicamente 0–8000 (tamaño del canvas)
  • Significado: posición vertical en píxeles del mapa
  • Validación: ninguna especial

rotation: int | None (opcional)

  • Tipo: entero o None
  • Default: 0
  • Rango: 0–360 (grados)
  • Significado: rotación visual del objeto en el mapa
  • Nota: Konva utiliza este valor para rotar el grupo del objeto

style_props: str | None (opcional)

  • Tipo: string JSON (no dict)
  • Default: "{}"
  • Estructura: JSON arbitrario según el tipo de objeto
  • Ejemplos:
    • Rectángulo clásico: {"color": "#1e1e1e", "width": 100, "height": 50}
    • Stencil: {"stencil": {"shapeId": "42u-rack-19-standard", "svg": "<svg>..."}, "width": 40, "height": 150}

Nota importante: se almacena como string en la BD (campo style_props: CharField en BlueprintPlacement), no como JSON serializado. El frontend es responsable de hacer JSON.stringify() antes de enviar.

name: str | None (v1.48.0 — nuevo)

  • Tipo: string o None
  • Default: None
  • Máx caracteres: 100 (tras limpieza)
  • Significado: nombre inicial del objeto al crearlo
    • Para racks: se usa como nombre del rack (Rack.name)
    • Para otros objetos: etiqueta opcional o descripción
  • Procesamiento: se limpia con .strip() y se trunca a 100 caracteres
  • Comportamiento en endpoint:
    • POST /api/blueprints/{bp_id}/rack: si no se proporciona, usa “New Rack”
    • Otros endpoints: depende del controlador específico

Validación

La validación ocurre en dos capas:

Capa Ninja/OpenAPI

  • Valida tipos (float para x/y, int para rotation, str para style_props/name)
  • Si los tipos no coinciden, devuelve 400 automáticamente

Capa de controlador

  • create_rack_in_blueprint() valida que el blueprint exista y pertenezca a la organización
  • name se limpia a máx 100 caracteres y se vacía si es todo espacios en blanco

Ejemplos de uso

Crear un rack con stencil (v1.48.0)

POST /api/blueprints/5/rack
Content-Type: application/json

{
  "x": 100.5,
  "y": 250.0,
  "rotation": 0,
  "name": "42U Rack Custom",
  "style_props": "{\"stencil\": {\"shapeId\": \"42u-rack-19-standard\", \"svg\": \"<svg>...</svg>\"}, \"width\": 40, \"height\": 150}"
}

Crear un rack clásico (rect)

POST /api/blueprints/5/rack
Content-Type: application/json

{
  "x": 300.0,
  "y": 400.0,
  "name": "Rack 2",
  "style_props": "{}"
}

→ Sin stencil, el endpoint crea el rack y el frontend lo pinta como rectángulo clásico.

Crear un placement genérico (dibujo)

POST /api/blueprints/5/placements
Content-Type: application/json

{
  "x": 50.0,
  "y": 100.0,
  "rotation": 45,
  "style_props": "{\"color\": \"#ff9900\", \"width\": 120, \"height\": 35}"
}

Cambios en v1.48.0

Lo nuevo: campo name

Motivación: El endpoint POST /api/blueprints/{bp_id}/rack necesitaba una forma de especificar el nombre inicial del rack sin hacer una llamada adicional de rename.

Impacto:

  • Los clientes antiguos que no envíen name siguen funcionando (compatibilidad regresiva)
  • Los clientes nuevos (Map Editor con stencils) envían name automáticamente
  • El campo se trunca a 100 caracteres por seguridad (evita inyección de datos enormes)

Flujo del Map Editor (v1.48.0)

  1. Usuario suelta un stencil de rack (ej: 42u-rack-19-standard)
  2. Frontend: StencilRenderer.insertRackStencil() → construye payload con:
    • name: shape.name (del catálogo de stencils)
    • x, y: posición del drop
    • style_props: JSON con stencil: { shapeId, svg }
  3. POST /api/blueprints/{bp_id}/rack con este payload
  4. Backend: crea Rack con nombre limpio (máx 100 chars) + almacena stencil en style_props
  5. Frontend: recibe la respuesta y pinta el visual con MapRacks.createRackNode()

Ubicación y referencias

  • Archivo: blueprints/api/schemas.py
  • Usado por endpoints:
    • blueprints_api_racks_create_rack_in_blueprint (POST /rack)
    • Otros endpoints de placement (si aplican)
  • Validación: Ninja realiza introspección automática

Testing

  • ✅ Valida tipos (x/y float, rotation int, name/style_props str)
  • ✅ Acepta name=None (regresivo)
  • ✅ Trunca name a 100 caracteres
  • ✅ Procesa style_props como string JSON (sin deserialización en el schema)

Notas

  • El campo style_props no se valida como JSON en el schema (la BD acepta cualquier string). El frontend es responsable de enviar JSON válido
  • name se limpia en el controlador, no en el schema (para evitar que el validador rechace un string con espacios en blanco al inicio)
  • El orden de campos en el JSON no importa (Ninja los une por nombre)

Véase también

  • [[entity—blueprints—endpoint—create-rack-in-blueprint]]
  • [[feature—blueprints—puente-rack-real]]
  • [[concept—blueprints—map-editor]]