Browse Source

Añado api

Celestino Rey 1 year ago
parent
commit
bdc99d20e9

+ 3 - 1
src/eventos/admin.py

@@ -10,7 +10,9 @@ admin.site.register(Noticia, NoticiaAdmin)
 
 
 class EventoAdmin(admin.ModelAdmin):
-    list_display = ['nombre', 'fecha', 'plazas_disponibles']
+    list_display = ['nombre', 'fecha', 'plazas_disponibles', 'url_imagen']
+    list_filter = ['publicado', 'fecha']
+    search_fields = ['titulo', 'descripcion']
 
 
 admin.site.register(Evento, EventoAdmin)

+ 0 - 0
src/eventos/management/__init__.py


+ 0 - 0
src/eventos/management/commands/__init__.py


+ 45 - 0
src/eventos/management/commands/importar_eventos.py

@@ -0,0 +1,45 @@
+import json
+from django.core.management.base import BaseCommand
+from repostajes.models import Evento
+
+
+class Command(BaseCommand):
+    help = "Importa eventos desde un archivo JSON"
+
+    def add_arguments(self, parser):
+        parser.add_argument('archivo_json', type=str, help="Ruta del archivo JSON")
+
+    def handle(self, *args, **kwargs):
+        archivo_json = kwargs['archivo_json']
+
+        try:
+            with open(archivo_json, 'r', encoding='utf-8') as file:
+                datos = json.load(file)
+
+            self.stdout.write(self.style.WARNING(f"\nSe encontraron {len(datos)} eventos en el archivo '{archivo_json}'."))
+            confirmar = input("¿Deseas continuar con la importación? (s/n): ").strip().lower()
+
+            if confirmar != 's':
+                self.stdout.write(self.style.ERROR("Importación cancelada."))
+                return
+
+            eventos_creados = 0
+            for evento_data in datos:
+                creado = Evento.objects.create(
+                    id=evento_data['id'],
+                    nombre=evento_data['nombre'],
+                    descripcion=evento_data['descripcion'],
+                    fecha=evento_data['fecha'],
+                    plazas_disponibles=evento_data['plazas_disponibles'],
+                    pubicado=evento_data['pubicado'],
+                    url_imagen=evento_data['url_imagen']
+                )
+                if creado:
+                    eventos_creados += 1
+
+            self.stdout.write(self.style.SUCCESS(f'Se importaron {eventos_creados} eventos correctamente.'))
+
+        except FileNotFoundError:
+            self.stderr.write(self.style.ERROR(f"El archivo {archivo_json} no se encontró."))
+        except json.JSONDecodeError:
+            self.stderr.write(self.style.ERROR("Error al leer el archivo JSON. Asegúrate de que el formato sea correcto."))

+ 49 - 0
src/eventos/management/commands/importar_listaespera.py

@@ -0,0 +1,49 @@
+import json
+from django.core.management.base import BaseCommand
+from eventos.models import ListaEspera, Evento
+from reymotausers.models import ReyMotaUser
+
+
+class Command(BaseCommand):
+    help = "Importa listaesperas desde un archivo JSON"
+
+    def add_arguments(self, parser):
+        parser.add_argument('archivo_json', type=str, help="Ruta del archivo JSON")
+
+    def handle(self, *args, **kwargs):
+        archivo_json = kwargs['archivo_json']
+
+        try:
+            with open(archivo_json, 'r', encoding='utf-8') as file:
+                datos = json.load(file)
+
+            self.stdout.write(self.style.WARNING(f"\nSe encontraron {len(datos)} listaesperas en el archivo '{archivo_json}'."))
+            confirmar = input("¿Deseas continuar con la importación? (s/n): ").strip().lower()
+
+            if confirmar != 's':
+                self.stdout.write(self.style.ERROR("Importación cancelada."))
+                return
+
+            listaesperas_creados = 0
+            for listaespera_data in datos:
+                try:
+                    evento = Evento.objects.get(id=listaespera_data["evento"])
+                    usuario = ReyMotaUser.objects.get(id=listaespera_data["usuario"])
+
+                    creado = ListaEspera.objects.create(
+                        evento_id=evento.id,
+                        usuario_id=usuario.id,
+                        fecha_apuntado=listaespera_data['fecha_apuntado'],
+                    )
+                    if creado:
+                        listaesperas_creados += 1
+
+                except Evento.DoesNotExist:
+                    self.stderr.write(self.style.ERROR(f"Evento '{listaespera_data['evento']}' no encontrado."))
+
+            self.stdout.write(self.style.SUCCESS(f'Se importaron {listaesperas_creados} listaesperas correctamente.'))
+
+        except FileNotFoundError:
+            self.stderr.write(self.style.ERROR(f"El archivo {archivo_json} no se encontró."))
+        except json.JSONDecodeError:
+            self.stderr.write(self.style.ERROR("Error al leer el archivo JSON. Asegúrate de que el formato sea correcto."))

+ 49 - 0
src/eventos/management/commands/importar_noticias.py

@@ -0,0 +1,49 @@
+import json
+from django.core.management.base import BaseCommand
+from eventos.models import Noticia
+from reymotausers.models import ReyMotaUser
+
+
+class Command(BaseCommand):
+    help = "Importa noticias desde un archivo JSON"
+
+    def add_arguments(self, parser):
+        parser.add_argument('archivo_json', type=str, help="Ruta del archivo JSON")
+
+    def handle(self, *args, **kwargs):
+        archivo_json = kwargs['archivo_json']
+
+        try:
+            with open(archivo_json, 'r', encoding='utf-8') as file:
+                datos = json.load(file)
+
+            self.stdout.write(self.style.WARNING(f"\nSe encontraron {len(datos)} noticias en el archivo '{archivo_json}'."))
+            confirmar = input("¿Deseas continuar con la importación? (s/n): ").strip().lower()
+
+            if confirmar != 's':
+                self.stdout.write(self.style.ERROR("Importación cancelada."))
+                return
+
+            noticias_creados = 0
+            for noticia_data in datos:
+                try:
+                    usuario = ReyMotaUser.objects.get(id=noticia_data["usuario"])
+
+                    creado = Noticia.objects.create(
+                        autor_id=usuario.id,
+                        titulo=noticia_data['titulo'],
+                        fecha_publicacion=noticia_data['fecha_publicacion'],
+                        publicado=noticia_data['publicado']
+                    )
+                    if creado:
+                        noticias_creados += 1
+
+                except ReyMotaUser.DoesNotExist:
+                    self.stderr.write(self.style.ERROR(f"Usuario '{noticia_data['usuario']}' no encontrado."))
+
+            self.stdout.write(self.style.SUCCESS(f'Se importaron {noticias_creados} noticias correctamente.'))
+
+        except FileNotFoundError:
+            self.stderr.write(self.style.ERROR(f"El archivo {archivo_json} no se encontró."))
+        except json.JSONDecodeError:
+            self.stderr.write(self.style.ERROR("Error al leer el archivo JSON. Asegúrate de que el formato sea correcto."))

+ 50 - 0
src/eventos/management/commands/importar_reservas.py

@@ -0,0 +1,50 @@
+import json
+from django.core.management.base import BaseCommand
+from eventos.models import Reserva, Evento
+from reymotausers.models import ReyMotaUser
+
+
+class Command(BaseCommand):
+    help = "Importa reservas desde un archivo JSON"
+
+    def add_arguments(self, parser):
+        parser.add_argument('archivo_json', type=str, help="Ruta del archivo JSON")
+
+    def handle(self, *args, **kwargs):
+        archivo_json = kwargs['archivo_json']
+
+        try:
+            with open(archivo_json, 'r', encoding='utf-8') as file:
+                datos = json.load(file)
+
+            self.stdout.write(self.style.WARNING(f"\nSe encontraron {len(datos)} reservas en el archivo '{archivo_json}'."))
+            confirmar = input("¿Deseas continuar con la importación? (s/n): ").strip().lower()
+
+            if confirmar != 's':
+                self.stdout.write(self.style.ERROR("Importación cancelada."))
+                return
+
+            reservas_creados = 0
+            for reserva_data in datos:
+                try:
+                    evento = Evento.objects.get(id=reserva_data["evento"])
+                    usuario = ReyMotaUser.objects.get(id=reserva_data["usuario"])
+
+                    creado = Reserva.objects.create(
+                        evento_id=evento.id,
+                        usuario_id=usuario.id,
+                        fecha_reserva=reserva_data['fecha_reserva'],
+                        evento=reserva_data['evento']
+                    )
+                    if creado:
+                        reservas_creados += 1
+
+                except Evento.DoesNotExist:
+                    self.stderr.write(self.style.ERROR(f"Evento '{reserva_data['evento']}' no encontrado."))
+
+            self.stdout.write(self.style.SUCCESS(f'Se importaron {reservas_creados} reservas correctamente.'))
+
+        except FileNotFoundError:
+            self.stderr.write(self.style.ERROR(f"El archivo {archivo_json} no se encontró."))
+        except json.JSONDecodeError:
+            self.stderr.write(self.style.ERROR("Error al leer el archivo JSON. Asegúrate de que el formato sea correcto."))

+ 1 - 0
src/eventos/models.py

@@ -11,6 +11,7 @@ class Evento(models.Model):
 
     plazas_disponibles = models.PositiveIntegerField()
     publicado = models.BooleanField(default=False)  # Nuevo campo para la publicación
+    url_imagen = models.TextField(blank=True, null=True)  # Campo para la URL de la imagen
 
     def __str__(self):
         return self.nombre

+ 26 - 0
src/eventos/serializers.py

@@ -0,0 +1,26 @@
+from rest_framework import serializers
+from .models import Evento, Reserva, ListaEspera, Noticia
+
+
+class EventoSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Evento
+        fields = '__all__'  # Incluir todos los campos del modelo
+
+
+class ReservaSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Reserva
+        fields = '__all__'  # Incluir todos los campos del modelo
+
+
+class ListaEsperaSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = ListaEspera
+        fields = '__all__'  # Incluir todos los campos del modelo
+
+
+class NoticiaSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Noticia
+        fields = '__all__'  # Incluir todos los campos del modelo

+ 17 - 0
src/eventos/urls.py

@@ -1,6 +1,11 @@
 from django.urls import path
 from . import views
 
+from .views import api_lista_eventos, api_detalle_evento
+from .views import api_lista_reservas, api_detalle_reserva
+from .views import api_lista_listaespera, api_detalle_listaespera
+from .views import api_lista_noticias, api_detalle_noticia
+
 app_name = 'eventos'
 
 urlpatterns = [
@@ -17,4 +22,16 @@ urlpatterns = [
 
     path('reservar/<int:evento_id>/',
          views.reservar_evento, name='reservar_evento'),
+
+    path('api/eventos/', api_lista_eventos, name='api_lista_eventos'),
+    path('api/eventos/<int:evento_id>/', api_detalle_evento, name='api_detalle_evento'),
+
+    path('api/reservas/', api_lista_reservas, name='api_lista_reservas'),
+    path('api/reservas/<int:reserva_id>/', api_detalle_reserva, name='api_detalle_reserva'),
+
+    path('api/listaespera/', api_lista_listaespera, name='api_lista_listaespera'),
+    path('api/listaespera/<int:listaespera_id>/', api_detalle_listaespera, name='api_detalle_listaespera'),
+
+    path('api/noticias/', api_lista_noticias, name='api_lista_noticias'),
+    path('api/noticias/<int:noticia_id>/', api_detalle_noticia, name='api_detalle_noticia'),
 ]

+ 94 - 4
src/eventos/views.py

@@ -4,6 +4,11 @@ from django.contrib import messages
 from django.core.mail import EmailMultiAlternatives
 from django.conf import settings
 from django.template.loader import render_to_string
+from django.utils import timezone
+
+from rest_framework.response import Response
+from rest_framework.decorators import api_view
+from .serializers import EventoSerializer, ReservaSerializer, ListaEsperaSerializer, NoticiaSerializer
 
 from .models import Evento, Reserva, ListaEspera, Noticia
 from .forms import ListaEsperaForm, EventoForm
@@ -72,11 +77,14 @@ def publicar_evento(request, evento_id):
 
 @login_required
 def lista_eventos(request):
+    # anno_actual = timezone.now().year
+
     # Solo mostrar los eventos publicados a los usuarios normales
     if request.user.is_staff:
-        eventos = Evento.objects.all()  # Los administradores ven todos los eventos
+        eventos = Evento.objects.all().order_by('-fecha', '-hora')
     else:
-        eventos = Evento.objects.filter(publicado=True)  # Los usuarios ven solo eventos publicados
+        eventos = Evento.objects.filter(publicado=True).order_by('-fecha', '-hora')
+#        eventos = Evento.objects.filter(publicado=True, fecha__year=anno_actual)  # Los usuarios ven solo eventos publicados y del año en curso
 
     # Crear un diccionario que mapea cada evento con un booleano indicando si el usuario ya ha reservado
     eventos_con_reserva = []
@@ -99,7 +107,8 @@ def lista_eventos(request):
             'plazas_restantes': evento.plazas_restantes,
             'en_espera': en_espera,
             'usuario': request.user,
-            'publicado': evento.publicado
+            'publicado': evento.publicado,
+            'url_imagen': evento.url_imagen
         })
 
     return render(request, 'eventos/lista_eventos.html', {'eventos_con_reserva': eventos_con_reserva})
@@ -144,7 +153,8 @@ def detalle_evento(request, evento_id):
             'plazas_restantes': evento.plazas_restantes,
             'en_espera': en_espera,
             'usuario': request.user,
-            'publicado': evento.publicado
+            'publicado': evento.publicado,
+            'url_imagen': evento.url_imagen
         }
     )
 
@@ -202,3 +212,83 @@ def apuntar_lista_espera(request, evento_id):
 
     form = ListaEsperaForm()
     return render(request, 'eventos/apuntar_lista_espera.html', {'form': form, 'evento': evento})
+
+
+#
+# API
+#
+
+@api_view(['GET'])
+def api_lista_eventos(request):
+    """Devuelve la lista de todos los eventos."""
+    eventos = Evento.objects.all()
+    serializer = EventoSerializer(eventos, many=True)
+    return Response(serializer.data)
+
+
+@api_view(['GET'])
+def api_detalle_evento(request, evento_id):
+    """Devuelve los detalles de un evento específico."""
+    try:
+        evento = Evento.objects.get(id=evento_id)
+        serializer = EventoSerializer(evento)
+        return Response(serializer.data)
+    except Evento.DoesNotExist:
+        return Response({'error': 'Evento no encontrado'}, status=404)
+
+
+@api_view(['GET'])
+def api_lista_reservas(request):
+    """Devuelve la lista de todos los reservas."""
+    reservas = Reserva.objects.all()
+    serializer = ReservaSerializer(reservas, many=True)
+    return Response(serializer.data)
+
+
+@api_view(['GET'])
+def api_detalle_reserva(request, reserva_id):
+    """Devuelve los detalles de un reserva específico."""
+    try:
+        reserva = Reserva.objects.get(id=reserva_id)
+        serializer = ReservaSerializer(reserva)
+        return Response(serializer.data)
+    except Reserva.DoesNotExist:
+        return Response({'error': 'Reserva no encontrado'}, status=404)
+
+
+@api_view(['GET'])
+def api_lista_listaespera(request):
+    """Devuelve la lista de todos los listaespera."""
+    listaesperas = ListaEspera.objects.all()
+    serializer = ListaEsperaSerializer(listaesperas, many=True)
+    return Response(serializer.data)
+
+
+@api_view(['GET'])
+def api_detalle_listaespera(request, listaespera_id):
+    """Devuelve los detalles de un listaespera específico."""
+    try:
+        listaespera = ListaEspera.objects.get(id=listaespera_id)
+        serializer = ListaEsperaSerializer(listaespera)
+        return Response(serializer.data)
+    except ListaEspera.DoesNotExist:
+        return Response({'error': 'ListaEspera no encontrado'}, status=404)
+
+
+@api_view(['GET'])
+def api_lista_noticias(request):
+    """Devuelve la lista de todos los noticias."""
+    noticias = Noticia.objects.all()
+    serializer = NoticiaSerializer(noticias, many=True)
+    return Response(serializer.data)
+
+
+@api_view(['GET'])
+def api_detalle_noticia(request, noticia_id):
+    """Devuelve los detalles de un noticia específico."""
+    try:
+        noticia = Noticia.objects.get(id=noticia_id)
+        serializer = NoticiaSerializer(noticia)
+        return Response(serializer.data)
+    except Noticia.DoesNotExist:
+        return Response({'error': 'Noticia no encontrado'}, status=404)

+ 17 - 13
src/gestion_reservas/settings.py

@@ -26,7 +26,7 @@ SECRET_KEY = 'hey'
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = os.environ["DEBUG"] == 'True'
 
-ALLOWED_HOSTS = [".ocp-cluster.reymota.lab"]
+ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")
 
 
 # Application definition
@@ -85,15 +85,16 @@ WSGI_APPLICATION = 'gestion_reservas.wsgi.application'
 
 DATABASES = {
     "default": {
-        "ENGINE": "django.db.backends.postgresql",
-        "NAME": "jugaralpadel",
-        "USER": "creylopez",
-        "PASSWORD": "Dsa-0213",
-        "HOST": "postgresql",
-        "PORT": "5432",
+        "ENGINE": os.environ.get("SQL_ENGINE", "django.db.backends.sqlite3"),
+        "NAME": os.environ.get("SQL_DATABASE", BASE_DIR / "db.sqlite3"),
+        "USER": os.environ.get("SQL_USER", "user"),
+        "PASSWORD": os.environ.get("SQL_PASSWORD", "password"),
+        "HOST": os.environ.get("SQL_HOST", "localhost"),
+        "PORT": os.environ.get("SQL_PORT", "5432"),
     }
 }
 
+
 # Password validation
 # https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
 
@@ -132,12 +133,9 @@ THOUSAND_SEPARATOR = '.'
 # Static files (CSS, JavaScript, Images)
 # https://docs.djangoproject.com/en/5.1/howto/static-files/
 
-STATIC_URL = 'static/'
+STATIC_URL = '/static/'
 STATIC_ROOT = BASE_DIR / "staticfiles"
 
-MEDIA_URL = '/media/'
-MEDIA_ROOT = BASE_DIR / "mediafiles"
-
 # Default primary key field type
 # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
 
@@ -149,7 +147,13 @@ LOGOUT_REDIRECT_URL = 'principal'
 
 AUTH_USER_MODEL = "reymotausers.ReyMotaUser"
 
-CSRF_TRUSTED_ORIGINS = ["https://*.ocp-cluster.reymota.lab"]
+MEDIA_ROOT = BASE_DIR / "mediafiles"
+MEDIA_URL = '/media/'
+
+if DEBUG is False:
+    CSRF_TRUSTED_ORIGINS = os.environ.get("CSRF_TRUSTED_ORIGINS").split(" ")
+
+CSRF_TRUSTED_ORIGINS = os.environ.get("CSRF_TRUSTED_ORIGINS").split(" ")
 
 # Configuración de correo con Gmail
 if DEBUG is True:
@@ -162,7 +166,7 @@ EMAIL_PORT = 587
 EMAIL_USE_TLS = True
 
 EMAIL_HOST_USER = 'jugaralpadelentreamigos@gmail.com'
-EMAIL_HOST_PASSWORD = 'oxdkclbtggewxhqc'  # Es mejor usar una contraseña de aplicación de Google
+EMAIL_HOST_PASSWORD = 'btjnlcliimxcnmhi'  # Es mejor usar una contraseña de aplicación de Google
 DEFAULT_FROM_EMAIL = 'jugaralpadelentreamigos@gmail.com'
 
 # Dirección del administrador

+ 1 - 3
src/gestion_reservas/urls.py

@@ -27,6 +27,7 @@ urlpatterns = [
     path('obreros/', admin.site.urls),
 
     path("eventos/", include('eventos.urls')),
+    path("usuarios/", include('reymotausers.urls')),
 
     path("accounts/", include("accounts.urls")),  # new
     path("accounts/", include("django.contrib.auth.urls")),
@@ -35,8 +36,5 @@ urlpatterns = [
     path('entorno/', views.ver_variables_entorno, name='ver_variables_entorno'),
     path('ayuda/', views.ayuda, name='ayuda'),
 
-    path('api/proximo-evento/', views.proximo_evento, name='proximo_evento'),
-    path('api/todos-los-eventos/', views.todos_los_eventos, name='todos_los_eventos'),
-
 ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
 

+ 0 - 48
src/gestion_reservas/views.py

@@ -1,5 +1,4 @@
 from rest_framework.response import Response
-from rest_framework.decorators import api_view
 from django.utils import timezone
 from rest_framework import status
 
@@ -52,53 +51,6 @@ def principal(request):
     return render(request, 'index.html', {'noticias': noticias})
 
 
-@api_view(['GET'])
-def proximo_evento(request):
-    # Obtiene y valida el parámetro `publicado`
-    publicado_param = request.GET.get('publicado', 'true').lower()
-    if publicado_param not in ['true', 'false', 'all']:
-        return Response(
-            {'detail': 'El parámetro "publicado" debe ser "true", "false" o "all".'},
-            status=status.HTTP_400_BAD_REQUEST
-        )
-
-    # Configura el filtro según el parámetro `publicado`
-    if publicado_param == 'all':
-        eventos = Evento.objects.filter(fecha__gte=timezone.now()).order_by('fecha')
-    else:
-        publicado = publicado_param == 'true'
-        eventos = Evento.objects.filter(publicado=publicado, fecha__gte=timezone.now()).order_by('fecha')
-
-    evento = eventos.first()
-
-    if evento:
-        serializer = EventoSerializer(evento)
-        return Response(serializer.data)
-    else:
-        return Response({'detail': 'No hay eventos próximos.'}, status=404)
-
-
-@api_view(['GET'])
-def todos_los_eventos(request):
-    # Obtiene y valida el parámetro `publicado`
-    publicado_param = request.GET.get('publicado', 'true').lower()
-    if publicado_param not in ['true', 'false', 'all']:
-        return Response(
-            {'detail': 'El parámetro "publicado" debe ser "true", "false" o "all".'},
-            status=status.HTTP_400_BAD_REQUEST
-        )
-
-    # Configura el filtro según el parámetro `publicado`
-    if publicado_param == 'all':
-        eventos = Evento.objects.all().order_by('fecha')
-    else:
-        publicado = publicado_param == 'true'
-        eventos = Evento.objects.filter(publicado=publicado).order_by('fecha')
-
-    serializer = EventoSerializer(eventos, many=True)  # `many=True` para serializar una lista de eventos
-    return Response(serializer.data)
-
-
 def ayuda(request):
     elementos_ayuda = Ayuda.objects.all().order_by('apartado')
     apartados = Ayuda.APARTADOS

+ 0 - 0
src/reymotausers/management/__init__.py


+ 0 - 0
src/reymotausers/management/commands/__init__.py


+ 48 - 0
src/reymotausers/management/commands/importar_usuarios.py

@@ -0,0 +1,48 @@
+import json
+from django.core.management.base import BaseCommand
+from reymotausers.models import ReyMotaUser
+
+
+class Command(BaseCommand):
+    help = "Importa usuarios desde un archivo JSON"
+
+    def add_arguments(self, parser):
+        parser.add_argument('archivo_json', type=str, help="Ruta del archivo JSON")
+
+    def handle(self, *args, **kwargs):
+        archivo_json = kwargs['archivo_json']
+
+        try:
+            with open(archivo_json, 'r', encoding='utf-8') as file:
+                datos = json.load(file)
+
+            self.stdout.write(self.style.WARNING(f"\nSe encontraron {len(datos)} usuarios en el archivo '{archivo_json}'."))
+            confirmar = input("¿Deseas continuar con la importación? (s/n): ").strip().lower()
+
+            if confirmar != 's':
+                self.stdout.write(self.style.ERROR("Importación cancelada."))
+                return
+
+            usuarios_creados = 0
+            for usuario_data in datos:
+                creado = ReyMotaUser.objects.create(
+                    foto=usuario_data['foto'],
+                    password=usuario_data['password'],
+                    is_superuser=usuario_data['is_superuser'],
+                    is_staff=usuario_data['is_staff'],
+                    is_active=usuario_data['is_active'],
+                    nombre=usuario_data['nombre'],
+                    email=usuario_data['email'],
+                    groups=usuario_data['groups'],
+                    user_permissions=usuario_data['user_permissions'],
+                    last_login=usuario_data['last_login']
+                )
+                if creado:
+                    usuarios_creados += 1
+
+            self.stdout.write(self.style.SUCCESS(f'Se importaron {usuarios_creados} usuarios correctamente.'))
+
+        except FileNotFoundError:
+            self.stderr.write(self.style.ERROR(f"El archivo {archivo_json} no se encontró."))
+        except json.JSONDecodeError:
+            self.stderr.write(self.style.ERROR("Error al leer el archivo JSON. Asegúrate de que el formato sea correcto."))

+ 8 - 0
src/reymotausers/serializers.py

@@ -0,0 +1,8 @@
+from rest_framework import serializers
+from .models import ReyMotaUser
+
+
+class ReyMotaUserSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = ReyMotaUser
+        fields = '__all__'  # Incluir todos los campos del modelo

+ 9 - 0
src/reymotausers/urls.py

@@ -0,0 +1,9 @@
+from django.urls import path
+
+from . import views
+from .views import api_lista_usuarios, api_detalle_usuario
+
+urlpatterns = [
+    path('api/usuarios/', api_lista_usuarios, name='api_lista_usuarios'),
+    path('api/usuarios/<int:usuario_id>/', api_detalle_usuario, name='api_detalle_usuario'),
+]

+ 26 - 0
src/reymotausers/views.py

@@ -1,3 +1,29 @@
 from django.shortcuts import render
 
+from rest_framework.response import Response
+from rest_framework.decorators import api_view
+
+from .serializers import ReyMotaUserSerializer
+
+from .models import ReyMotaUser
+
 # Create your views here.
+
+
+@api_view(['GET'])
+def api_lista_usuarios(request):
+    """Devuelve la lista de todos los usuarios."""
+    usuarios = ReyMotaUser.objects.all()
+    serializer = ReyMotaUserSerializer(usuarios, many=True)
+    return Response(serializer.data)
+
+
+@api_view(['GET'])
+def api_detalle_usuario(request, usuario_id):
+    """Devuelve los detalles de un usuario específico."""
+    try:
+        usuario = ReyMotaUser.objects.get(id=usuario_id)
+        serializer = ReyMotaUserSerializer(usuario)
+        return Response(serializer.data)
+    except ReyMotaUser.DoesNotExist:
+        return Response({'error': 'Canción no encontrada'}, status=404)