Rutas Vivas Service es el backend desarrollado en Django para la app móvil RutasVivas. Provee los endpoints necesarios para:
- Obtener hitos (landmarks) y estaciones (stations).
- Generar rutas emocionales (emotional routes) según mood y tiempo.
- Crear usuarios locales (UserLocal).
- Crear comentarios sobre hitos (landmark comments).
- Subir imágenes secundarias de hitos.
- Cargar masiva de hitos y exportar hitos en formato GeoJSON.
El proyecto incluye además un portal administrativo (Django admin) para gestionar hitos, estaciones y comentarios.
Nota: el
urls.pyexpone las rutas que se documentan a continuación. En entornoDEBUGel servidor sirveMEDIA_URLdesdeMEDIA_ROOT.
- Formato de intercambio: JSON para la mayoría de endpoints (excepto uploads multipart).
- Encabezados recomendados:
Content-Type: application/jsonpara JSON.Content-Type: multipart/form-datapara subida de archivos.Accept: application/json
- Códigos de respuesta comunes:
200 OK— petición correcta (GET, PUT que devuelven recurso).201 Created— recurso creado (POST).204 No Content— operación exitosa sin cuerpo (DELETE o POST sin retorno).400 Bad Request— validación fallida.401 Unauthorized/403 Forbidden— si se usa autenticación/permiso y falla.404 Not Found— recurso no existe.500 Internal Server Error— error servidor.
Nombre: EmotionalRouteView
Método: POST
Descripción: Genera una ruta emocional (secuencia de hitos y estaciones) según parámetros enviados por el cliente (mood, duración, posición inicial.). Se espera que la vista haga la lógica de selección y ordenamiento de hitos.
Request (application/json) — ejemplo recomendado:
{
"mood": "Neutro", // string: mood elegido (e.g., Neutro)
"duration_minutes": 45, // integer: duración total estimada en minutos
"start_location": {
//lat/lng para punto de inicio.
"lat": 11.000123,
"lng": -74.850321
}
}Response 200 (application/json) — ejemplo recomendado:
{
"route_id": "route_20251012_001",
"mood": "Neutro",
"duration_minutes": 45,
"estimated_distance_m": 3200,
"start_point": { "lat": 11.000123, "lng": -74.850321 },
"landmarks": [
{
"id": 12,
"name": "Hito Principal",
"description": "Descripción breve",
"lat": 11.0005,
"lng": -74.8509,
"sequence": 1,
"estimated_time_at_landmark_min": 5
},
{
"id": 7,
"name": "Plaza central",
"lat": 11.0012,
"lng": -74.851,
"sequence": 2
}
],
"geojson": {
/* opcional: GeoJSON FeatureCollection del trayecto */
}
}Errores comunes:
400simood,duration_minutesostart_locationfaltan o son inválidos.500si la generación falla por error interno.
Observaciones y recomendaciones:
- Es preferible devolver también una representación GeoJSON del trayecto (FeatureCollection con
LineStringdel path yPointpara cada landmark) para que el cliente lo pinte directamente en el mapa. - Añadir
route_idpermite al backend guardar recorrido finalizado o reconsultarlo.
Nombre: landmarks_geojson
Método: GET
Descripción: Devuelve todos los hitos como un GeoJSON FeatureCollection. Útil para cargar capas en flutter_map sin transformación adicional.
Query parameters (opcionales):
bbox— bounding box en formatominLng,minLat,maxLng,maxLatpara filtrar por área.mood— para filtrar hitos por mood categorizado.limit,offset— paginación.
Response 200 (application/geo+json) — ejemplo:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": 12,
"properties": {
"name": "Hito Principal",
"description": "Texto...",
"category": "historia",
"images": [
"/media/landmarks/12/main.jpg",
"/media/landmarks/12/secondary_1.jpg"
],
"info_url": "/api/landmarks/12/"
},
"geometry": {
"type": "Point",
"coordinates": [-74.850900, 11.000500]
}
},
...
]
}Errores comunes:
400sibboxmalformado.500por errores de serialización.
Observaciones:
- Content-Type ideal:
application/geo+jsonoapplication/json. - Para performance, soportar filtrado por bbox y paginación.
Nombre: LandmarkBulkCreateView Método: POST Descripción: Endpoint para creación masiva de hitos (bulk). Se usa para importar datasets (CSV/JSON) desde herramientas administrativas o scripts de migración.
Request (application/json) — ejemplo:
{
"landmarks": [
{
"external_id": "L-001",
"name": "Hito A",
"description": "Descripción A",
"lat": 11.0001,
"lng": -74.8501,
"category": "arte",
"images": [],
"meta": { "difficulty": "low" }
},
{
"external_id": "L-002",
"name": "Hito B",
"lat": 11.0002,
"lng": -74.8502
}
],
"validate_only": false // opcional: si true, valida sin persistir
}Response 201 (application/json) — ejemplo:
{
"created": 2,
"errors": []
}Response 207 Multi-Status — si algunos elementos fallan; recomendable devolver array con resultados por elemento:
{
"results": [
{ "external_id": "L-001", "status": 201, "id": 12 },
{
"external_id": "L-002",
"status": 400,
"errors": { "lat": ["Campo requerido"] }
}
]
}Errores comunes:
400si el body no contienelandmarkso está mal formado.- Validaciones por item devueltas en array.
Observaciones:
- Implementar validación por item y transacciones parciales (configurable).
- Aceptar también CSV mediante
multipart/form-datacon procesamiento server-side puede ser útil.
Nombre: LandmarkImageUploadView
Método: POST
Descripción: Subida de imagen secundaria (o primaria) para un hito. Endpoint dirigido a recibir archivos multimedia y asociarlos al landmark_id.
Request (multipart/form-data) — campos:
image(archivo) — requerido.is_primary(boolean) — opcional.alt(string) — texto alternativo.
Curl ejemplo:
curl -X POST "https://api.example.com/landmarks/12/upload-image/" \
-F "image=@/path/to/photo.jpg" \
-F "is_primary=false" \
-H "Authorization: Token <token>"Nota: puede apoyarse del portal administrativo para gestionar imágenes de una manera más amigable.
Response 201 (application/json) — ejemplo:
{
"id": 34,
"landmark": 12,
"image_url": "/media/landmarks/12/secondary_34.jpg",
"is_primary": false,
"uploaded_at": "2025-10-12T15:00:00Z"
}Errores comunes:
400si faltan campos o tipo de archivo inválido.404silandmark_idno existe.413 Payload Too Largesi el archivo excede límites.
Observaciones:
- Asegurarse de validar el tipo MIME y limitar tamaño.
- Usar
ImageFieldconPillowpara validación y generación de thumbnails si se requiere.
Nombre: StationListView Método: GET Descripción: Lista estaciones definidas en el sistema. Debe devolver colección paginada con datos relevantes.
Query params (opcionales):
page,page_sizenear(lat,lng) — para ordenar por proximidadbbox— para filtrar área
Response 200 (application/json) — ejemplo:
{
"count": 12,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "Estación Norte",
"description": "Punto de encuentro",
"lat": 11.002,
"lng": -74.852,
"capacity": 50
},
...
]
}Errores comunes:
400por parámetros inválidos.
Nombre: StationCreateView Método: POST Descripción: Crea una nueva estación.
Request (application/json) — ejemplo:
{
"name": "Estación Sur",
"description": "Descripción",
"lat": 11.003,
"lng": -74.853,
"capacity": 20
}Response 201 (application/json) — ejemplo:
{
"id": 13,
"name": "Estación Sur",
"lat": 11.003,
"lng": -74.853
}Errores comunes:
400si faltan campos requeridos o lat/lng inválidos.
Nombre: UserLocalCreateView Método: POST Descripción: Crea un usuario local. Útil para asociar recorridos y comentarios a un identificador local.
Request (application/json) — ejemplo:
{
"username": "visitante_123",
"display_name": "Andrés",
"metadata": { "device": "android", "app_version": "0.1.0" }
}Response 201 (application/json):
{
"id": "local_abc123",
"username": "visitante_123",
"display_name": "Andrés",
"created_at": "2025-10-12T15:10:00Z"
}Errores comunes:
400campos requeridos faltantes.
Observaciones:
- Decidir si
UserLocalrepresenta un modelo persistente o una entidad temporal. Para métricas y comentarios es conveniente persistir un identificador.
Nombre: LandmarkCommentCreateView Método: POST Descripción: Crea un comentario asociado a un hito (landmark). Se usa por la app al finalizar un recorrido o al interactuar con información del hito.
Request (application/json) — ejemplo:
{
"landmark_id": 12,
"user_id": "local_abc123", // o user: {id, username}
"rating": 4, // opcional: calificación numérica
"comment": "Me gustó mucho la historia del lugar."
}Response 201 (application/json) — ejemplo:
{
"id": 55,
"landmark": 12,
"user_id": "local_abc123",
"rating": 4,
"comment": "Me gustó mucho la historia del lugar.",
"created_at": "2025-10-12T15:15:00Z"
}Errores comunes:
400silandmark_idocommentfaltan.404silandmark_idno existe.
A continuación propongo los campos más probables para cada entidad según la funcionalidad; revisa y ajusta según tus modelos reales.
id: AutoFieldexternal_id: CharField(opcional)name: CharFieldslug: SlugField(opcional)description: TextFieldlat: FloatFieldlng: FloatFieldcategory: CharField(mood tags / categories)main_image: ImageField(opcional)secondary_images: ManyToMany -> LandmarkImageo relación a tablaLandmarkImagecreated_at,updated_atmeta: JSONField(opcional para datos adicionales)
idlandmark: ForeignKey(Landmark)image: ImageFieldis_primary: BooleanFieldalt: CharFielduploaded_at
idnamedescriptionlat,lngcapacity(int)created_at
id(string o uuid)usernamedisplay_namemetadata: JSONFieldcreated_at
idlandmark: ForeignKey(Landmark)user: ForeignKey(UserLocal)(o nullable si anónimo)rating: IntegerField(opcional)comment: TextFieldapproved: BooleanField(por moderación)created_at
idmoodduration_minutesuser(FK opcional)landmarks: ManyToMany(Landmark, through=RouteSequence)con orden/sequencegeojson: JSONFieldcreated_at
-
El backend aprovecha el admin de Django para gestionar:
- Hitos, imágenes, estaciones, comentarios y usuarios locales.
-
Recomiendo usar
list_display,search_fieldsy filtros porcategoryycreated_at. -
Añadir acciones admin para aprobar comentarios en lote.
Dentro de la carpeta
/docsva a encontrar un video explicativo de cómo usar el portal administrativo. ademas anexo las credenciales para dicho portal.
- Usuario:
admin - Contraseña:
admin123
- Lat/Lng: validar rango válido (lat ∈ [-90,90], lng ∈ [-180,180]).
- Duración de rutas: rango mínimo/máximo (ej. 5–240 min).
- Subida de imágenes: validar tamaño y tipo MIME (jpg/png), generar thumbnails.
- Comentarios: limitar longitud, sanitizar contenido y asociar moderación.
- Bulk create: validar por item y devolver resultados parciales (no fallar todo por un item inválido).
- Usar siempre campos en snake_case en JSON para consistencia (
duration_minutes,start_location). - Incluir
idnumérico yurlodetail_urlcuando aplique para facilitar hipermedia. - Para colecciones usar paginación estándar
{count, next, previous, results}.
- Estructura de modelos y campos: inferida de las rutas y nombres de vistas — debes verificar los nombres exactos de campos en
models.py. - Formato exacto de
emotional-routeresponse: propuesto para máxima utilidad (IDs, sequence y geojson). Si tu vista actual devuelve otra cosa, puedo adaptar la documentación al formato real. - Autenticación: no se especifica en
urls.py; documenté endpoints como abiertos y propuse cómo protegerlos si se requiere. - Bulk create y GeoJSON: comportamientos estándar asumidos (bulk JSON array y FeatureCollection respectivamente).
Este documento ofrece una especificación técnica completa y utilizable. Permite a desarrolladores frontend y otros integrarse con el backend de Rutas Vivas de manera efectiva, entendiendo qué esperar de cada endpoint, cómo interactuar con ellos y qué validaciones se aplican.
© 2025 — Rutas Vivas Service — Documentación API (español técnico)