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 realPOST /api/blueprints/{bp_id}/placements— crear un placement genéricoPUT /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}
- Rectángulo clásico:
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
- Para racks: se usa como nombre del rack (
- 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ónnamese 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
namesiguen funcionando (compatibilidad regresiva) - Los clientes nuevos (Map Editor con stencils) envían
nameautomáticamente - El campo se trunca a 100 caracteres por seguridad (evita inyección de datos enormes)
Flujo del Map Editor (v1.48.0)
- Usuario suelta un stencil de rack (ej:
42u-rack-19-standard) - Frontend:
StencilRenderer.insertRackStencil()→ construye payload con:name: shape.name(del catálogo de stencils)x, y: posición del dropstyle_props: JSON constencil: { shapeId, svg }
- POST
/api/blueprints/{bp_id}/rackcon este payload - Backend: crea
Rackcon nombre limpio (máx 100 chars) + almacena stencil enstyle_props - 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
namea 100 caracteres - ✅ Procesa
style_propscomo string JSON (sin deserialización en el schema)
Notas
- El campo
style_propsno se valida como JSON en el schema (la BD acepta cualquier string). El frontend es responsable de enviar JSON válido namese 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]]