Se ha implementado la API REST completa para el sistema de gestión de competiciones, producciones y archivos.
Editions (dpms/compos/serializers/editions.py):
EditionListSerializer- Lista mínima de edicionesEditionSerializer- CRUD estándarEditionDetailSerializer- Detalle con compos anidadasHasCompoInlineSerializer- Para mostrar compos dentro de ediciones
Compos (dpms/compos/serializers/compos.py):
CompoSerializer- CRUD estándar de tipos de competicionesCompoDetailSerializer- Detalle con ediciones asociadasHasCompoSerializer- Gestión de relación Edition↔Compo
Productions (dpms/compos/serializers/productions.py):
ProductionSerializer- Lista de produccionesProductionDetailSerializer- Detalle con archivos anidadosProductionCreateSerializer- Crear/actualizar con validaciones
Files (dpms/compos/serializers/files.py):
FileSerializer- Lista de archivosFileUploadSerializer- Subir archivos (multipart)FileUpdateSerializer- Actualizar metadata
- EditionViewSet - Gestión de ediciones/eventos
- CompoViewSet - Gestión de tipos de competiciones
- HasCompoViewSet - Configuración Edition↔Compo
- ProductionViewSet - Envío y gestión de producciones
- FileViewSet - Subida y descarga de archivos
IsAdminOrReadOnly- Solo admins editan, todos leenIsOwnerOrAdmin- Solo dueño o admin editanIsOwner- Solo el dueño edita
GET /api/editions/ # Listar ediciones
POST /api/editions/ # Crear edición (admin)
GET /api/editions/{id}/ # Detalle de edición
PUT /api/editions/{id}/ # Actualizar (admin)
DELETE /api/editions/{id}/ # Eliminar (admin)
GET /api/editions/{id}/compos/ # Compos de esta edición
GET /api/editions/{id}/productions/ # Producciones de esta edición
Query params en /api/editions/:
public=true- Solo ediciones públicasopen_to_upload=true- Solo las que aceptan envíos
GET /api/compos/ # Listar competiciones
POST /api/compos/ # Crear compo (admin)
GET /api/compos/{id}/ # Detalle de compo
PUT /api/compos/{id}/ # Actualizar (admin)
DELETE /api/compos/{id}/ # Eliminar (admin)
GET /api/compos/{id}/productions/ # Producciones de esta compo
GET /api/hascompos/ # Listar asociaciones
POST /api/hascompos/ # Crear asociación (admin)
GET /api/hascompos/{id}/ # Detalle
PUT /api/hascompos/{id}/ # Actualizar config (admin)
DELETE /api/hascompos/{id}/ # Eliminar asociación (admin)
Query params en /api/hascompos/:
edition={id}- Filtrar por edicióncompo={id}- Filtrar por compo
GET /api/productions/ # Listar producciones
POST /api/productions/ # Enviar producción (auth)
GET /api/productions/{id}/ # Detalle con archivos
PUT /api/productions/{id}/ # Actualizar (owner/admin)
DELETE /api/productions/{id}/ # Eliminar (owner/admin)
GET /api/productions/my-productions/ # Mis producciones (auth)
Query params en /api/productions/:
edition={id}- Filtrar por edicióncompo={id}- Filtrar por compomy_productions=true- Solo las mías
GET /api/files/ # Listar mis archivos (auth)
POST /api/files/ # Subir archivo (multipart, auth)
GET /api/files/{id}/ # Detalle de archivo
PUT /api/files/{id}/ # Actualizar metadata (owner/admin)
DELETE /api/files/{id}/ # Eliminar archivo (owner/admin)
GET /api/files/{id}/download/ # Descargar archivo
ProductionCreateSerializer:
- ✅ Verifica que
edition.open_to_upload == True - ✅ Verifica que
HasCompo.open_to_upload == True - ✅ Verifica que la compo existe en esa edición
- ✅ Verifica que los archivos pertenecen al usuario actual
- ✅ Al actualizar: verifica que
open_to_update == True
FileUploadSerializer:
- ✅ Límite de tamaño: 100MB máximo
- ✅ Almacena
original_filenameautomáticamente - ✅ Genera nombre UUID único
HasCompoSerializer:
- ✅ Previene duplicados (misma edition+compo)
| Endpoint | Acción | Permiso |
|---|---|---|
/api/editions/ |
GET | AllowAny (solo públicas si no auth) |
/api/editions/ |
POST/PUT/DELETE | IsAuthenticated + IsAdminUser |
/api/compos/ |
GET | AllowAny |
/api/compos/ |
POST/PUT/DELETE | IsAuthenticated + IsAdminUser |
/api/productions/ |
GET | AllowAny |
/api/productions/ |
POST | IsAuthenticated |
/api/productions/{id}/ |
PUT/DELETE | IsAuthenticated + IsOwnerOrAdmin |
/api/files/ |
* | IsAuthenticated + IsOwnerOrAdmin |
Los archivos NO se eliminan físicamente, se marcan como is_deleted=True:
def perform_destroy(self, instance):
instance.is_deleted = True
instance.is_active = False
instance.save()curl -X POST http://localhost:8000/api/editions/ \
-H "Authorization: Token YOUR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Posadas Party 2025",
"description": "Demo party en Posadas",
"public": true,
"open_to_upload": true,
"open_to_update": false
}'curl -X POST http://localhost:8000/api/compos/ \
-H "Authorization: Token YOUR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo",
"description": "Competición de demos"
}'curl -X POST http://localhost:8000/api/hascompos/ \
-H "Authorization: Token YOUR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"edition": 1,
"compo": 1,
"start": "2025-12-20T20:00:00Z",
"show_authors_on_slide": true,
"open_to_upload": true,
"open_to_update": true
}'curl -X POST http://localhost:8000/api/files/ \
-H "Authorization: Token YOUR_USER_TOKEN" \
-F "file=@/path/to/demo.zip" \
-F "title=My Demo File" \
-F "description=Demo executable" \
-F "public=false"curl -X POST http://localhost:8000/api/productions/ \
-H "Authorization: Token YOUR_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "My Awesome Demo",
"authors": "DemoGroup",
"description": "A great demo!",
"edition": 1,
"compo": 1,
"files": [1, 2]
}'curl http://localhost:8000/api/editions/1/productions/curl -H "Authorization: Token YOUR_USER_TOKEN" \
http://localhost:8000/api/productions/my-productions/curl -H "Authorization: Token YOUR_USER_TOKEN" \
http://localhost:8000/api/files/1/download/ \
--output demo.zipbackend/dpms/compos/
├── serializers/
│ ├── __init__.py ✅ Exports
│ ├── editions.py ✅ 4 serializers
│ ├── compos.py ✅ 3 serializers
│ ├── productions.py ✅ 3 serializers
│ └── files.py ✅ 3 serializers
├── views/
│ ├── __init__.py ✅ Exports
│ ├── editions.py ✅ EditionViewSet
│ ├── compos.py ✅ CompoViewSet + HasCompoViewSet
│ ├── productions.py ✅ ProductionViewSet
│ └── files.py ✅ FileViewSet
├── permissions.py ✅ 3 permisos personalizados
└── urls.py ✅ Router con 5 viewsets
Total:
- 13 serializers
- 5 ViewSets
- 3 permisos personalizados
- ~30 endpoints API
- Registrarse →
POST /api/users/signup/ - Verificar email →
GET /api/users/verify/?token=... - Login →
POST /api/users/login/ - Ver ediciones abiertas →
GET /api/editions/?open_to_upload=true - Ver compos disponibles →
GET /api/editions/{id}/compos/ - Subir archivos →
POST /api/files/(multipart) - Enviar producción →
POST /api/productions/ - Ver mis producciones →
GET /api/productions/my-productions/ - Actualizar producción →
PUT /api/productions/{id}/(si aún permitido)
- Login como admin
- Crear edición →
POST /api/editions/ - Crear compos →
POST /api/compos/ - Asociar compos a edición →
POST /api/hascompos/ - Abrir/cerrar envíos →
PATCH /api/hascompos/{id}/(cambiaropen_to_upload) - Ver producciones enviadas →
GET /api/editions/{id}/productions/ - Moderar →
PUT/DELETE /api/productions/{id}/
- ✅ La edición debe estar
open_to_upload=true - ✅ El HasCompo debe estar
open_to_upload=true - ✅ La compo debe existir en esa edición (HasCompo)
- ✅ Los archivos deben pertenecer al usuario actual
- ✅ Usuario debe estar autenticado y verificado
- ✅ El usuario debe ser el owner o admin
- ✅ La edición debe estar
open_to_update=true - ✅ El HasCompo debe estar
open_to_update=true
- ✅ Tamaño máximo: 100MB
- ✅ Usuario debe estar autenticado
- ✅ Se guarda el
original_filename - ✅ Se genera nombre único con UUID
La API está completamente funcional pero falta el frontend React:
-
Componentes a crear:
ComposList.js- Ver competicionesProductionForm.js- Formulario de envíoMyProductions.js- Mis produccionesFileUpload.js- Componente de subidaProductionDetail.js- Ver detalle
-
Rutas a añadir:
/app/compos/app/my-productions/app/productions/new/app/productions/:id
-
Navegación:
- Añadir enlaces en MainBar
- Dashboard con resumen
- Archivos creados: 8
- Líneas de código: ~1,500
- Serializers: 13
- ViewSets: 5
- Endpoints: ~30
- Permisos: 3 personalizados
- Validaciones: 10+ reglas de negocio
# 1. Ver endpoints disponibles
curl http://localhost:8000/api/editions/
curl http://localhost:8000/api/compos/
curl http://localhost:8000/api/productions/
# 2. Ver Swagger docs
open http://localhost:8000/docs/
# 3. Ver URLs registradas
docker compose -f local.yml exec backend_party python manage.py show_urls | grep api¡API de Competiciones completamente implementada y funcionando! 🎉