From 70df69212d4a7129a343f66b125593aad34383d9 Mon Sep 17 00:00:00 2001 From: AdalbertoCV <34152734@uaz.edu.mx> Date: Tue, 20 Aug 2024 18:17:27 -0600 Subject: [PATCH 1/3] =?UTF-8?q?Formulario=20din=C3=A1mcio=20agregado=20en?= =?UTF-8?q?=20el=20get=20de=20tablas=20din=C3=A1micas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cosiap_api/delete_migrations.py | 21 ++++++++ cosiap_api/dynamic_tables/DynamicTable.py | 8 ++- .../dynamic_tables/DynamicTableDynamicForm.py | 51 +++++++++++++++++-- cosiap_api/dynamic_tables/views.py | 24 ++++++--- cosiap_api/solicitudes/views.py | 1 + 5 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 cosiap_api/delete_migrations.py diff --git a/cosiap_api/delete_migrations.py b/cosiap_api/delete_migrations.py new file mode 100644 index 0000000..d97a979 --- /dev/null +++ b/cosiap_api/delete_migrations.py @@ -0,0 +1,21 @@ +import os +import shutil + +def delete_migrations(project_dir): + for root, dirs, files in os.walk(project_dir): + if 'migrations' in dirs: + migrations_dir = os.path.join(root, 'migrations') + print(f"Eliminando archivos de migración en: {migrations_dir}") + # Borra todos los archivos en el directorio de migraciones, excepto el archivo __init__.py + for filename in os.listdir(migrations_dir): + file_path = os.path.join(migrations_dir, filename) + if filename != '__init__.py' and filename.endswith('.py'): + print(f"Eliminando archivo: {file_path}") + os.remove(file_path) + # Si quieres eliminar también el archivo __init__.py, descomenta la siguiente línea + # shutil.rmtree(migrations_dir) + print(f"Archivos de migración eliminados en: {migrations_dir}") + +if __name__ == "__main__": + project_dir = os.path.dirname(os.path.abspath(__file__)) + delete_migrations(project_dir) diff --git a/cosiap_api/dynamic_tables/DynamicTable.py b/cosiap_api/dynamic_tables/DynamicTable.py index c9f0e6d..958047a 100644 --- a/cosiap_api/dynamic_tables/DynamicTable.py +++ b/cosiap_api/dynamic_tables/DynamicTable.py @@ -23,7 +23,7 @@ from zipfile import ZipFile import io from dynamic_forms.models import RDocumento -exclude_pattern = re.compile(r'^password$|^last_login$|^created_at$|^updated_at$|^usuario_ptr$|^groups$|^user_permissions$|^dynamic_form$', re.IGNORECASE) +exclude_pattern = re.compile(r'^password$|^last_login$|^created_at$|^updated_at$|^usuario_ptr$|^groups$|^user_permissions$|^dynamic_form__nombre$|^dynamic_form__secciones$', re.IGNORECASE) class DynamicTable(serializers.ModelSerializer): ''' @@ -36,6 +36,12 @@ class DynamicTable(serializers.ModelSerializer): fields = '__all__' + def __init__(self, model_class=None, *args, **kwargs): + if model_class is None: + raise ValueError("El argumento 'model_class' es obligatorio.") + self.model_class = model_class + + def to_representation(self, instance): ''' Método to_representation: Devuelve la representación de la configuración de tabla dinámica excluyendo la data diff --git a/cosiap_api/dynamic_tables/DynamicTableDynamicForm.py b/cosiap_api/dynamic_tables/DynamicTableDynamicForm.py index 94503d7..73a3c69 100644 --- a/cosiap_api/dynamic_tables/DynamicTableDynamicForm.py +++ b/cosiap_api/dynamic_tables/DynamicTableDynamicForm.py @@ -1,10 +1,53 @@ from .DynamicTable import DynamicTable +from dynamic_forms.models import DynamicForm +from solicitudes.models import Solicitud +from dynamic_forms.serializers import OpcionSerializer, ElementosOpcionesSerializer, ElementoSerializer, SeccionesElementosSerializer, SeccionSerializer, DynamicFormsSeccionesSerializer, DynamicFormSerializer, RespuestaFormularioSerializer + class DynamicTableDynamicForm(DynamicTable): - - def get_dynamicform_fields(self): - ''' Aquí se realizará la lógica para la obtención de las columnas del dynamic_form''' - pass + ''' + Clase que hereda de DynamicTable con el objetivo de especializar su comportamiento para la extracción de los + datos de un formulario dinámico + ''' + + + def get_data(self, obj): + ''' + Método sobreescrito para obtener los datos tanto de la solicitud como de el formulario + dinámico asociado a ella. + ''' + solicitudes = super().get_data(obj) + solicitud_ids = [solicitud.get('id') for solicitud in solicitudes if solicitud.get('id')] + solicitud_instances = Solicitud.objects.filter(id__in=solicitud_ids).select_related('modalidad__dynamic_form') + + # Serializar las solicitudes utilizando RespuestaFormularioSerializer, pasando dynamic_form_source como parámetro + serialized_forms = RespuestaFormularioSerializer(solicitud_instances, many=True, dynamic_form_source='modalidad__dynamic_form') + + forms_data = serialized_forms.data + forms_data_dict = {form['id']: form for form in forms_data} + + for solicitud in solicitudes: + dynamic_form_id = solicitud.get('modalidad__dynamic_form__id') + if dynamic_form_id: + solicitud['formulario'] = forms_data_dict.get(dynamic_form_id) + + return solicitudes + + def retrieve_instance_data(self, instance): + ''' + Método sobreescrito para la vista detallada de la solicitud incluyendo su formulario dinámico + ''' + solicitud = super().retrieve_instance_data(instance) + solicitud_id = solicitud.get('id') + solicitud_instance = Solicitud.objects.get(id=solicitud_id) + + form = RespuestaFormularioSerializer(solicitud_instance, dynamic_form_source='modalidad__dynamic_form') + form_data = form.data + + solicitud['formulario'] = form_data + + return solicitud + def get_dynamicform_filters(self): ''' Aquí se realizará la lógica para la obtención de los filtros disponibles de dynamic_form''' diff --git a/cosiap_api/dynamic_tables/views.py b/cosiap_api/dynamic_tables/views.py index e994cc2..20ed81f 100644 --- a/cosiap_api/dynamic_tables/views.py +++ b/cosiap_api/dynamic_tables/views.py @@ -2,6 +2,7 @@ from django.shortcuts import render, get_object_or_404 from rest_framework.response import Response from rest_framework import status from dynamic_tables.DynamicTable import DynamicTable +from dynamic_tables.DynamicTableDynamicForm import DynamicTableDynamicForm from rest_framework.permissions import AllowAny, IsAuthenticated from dynamic_tables.models import DynamicTableReport from users.views import BasePermissionAPIView @@ -20,7 +21,7 @@ class DynamicTableAPIView(BasePermissionAPIView): ''' permission_classes_update = [IsAuthenticated, es_admin] - permission_classes_list = [IsAuthenticated, es_admin] + permission_classes_list = [IsAuthenticated, es_admin] permission_classes_create = [IsAuthenticated, es_admin] permission_classes_delete = [IsAuthenticated, es_admin] @@ -34,6 +35,8 @@ class DynamicTableAPIView(BasePermissionAPIView): # Lista con los campos que no pueden ser modificados mediante la solicitud put non_editable_fields = [] + dynamic_form_exist = False + def get_configuracion_reporte(self, request): ''' Crear una configuración con los datos actuales de la request, sobrescribiendo los predeterminados si se proporcionan. @@ -89,15 +92,21 @@ class DynamicTableAPIView(BasePermissionAPIView): if pk is not None: # Recuperar la instancia y extraer los datos instance = get_object_or_404(self.model_class, pk=pk) - serializer = DynamicTable() + if self.dynamic_form_exist: + serializer = DynamicTableDynamicForm(model_class=self.model_class) + else: + serializer = DynamicTable() instance_data = serializer.retrieve_instance_data(instance) return Response(instance_data, status=status.HTTP_200_OK) try: configuracion_reporte = self.get_configuracion_reporte(request) - serializer = DynamicTable(instance=configuracion_reporte) + if self.dynamic_form_exist: + serializer = DynamicTableDynamicForm(instance=configuracion_reporte, model_class=self.model_class) + else: + serializer = DynamicTable(instance=configuracion_reporte,model_class=self.model_class) data = serializer.get_data(configuracion_reporte) - available_filters = serializer.get_available_filters(configuracion_reporte) available_columns = serializer.get_available_columns(configuracion_reporte) + available_filters = serializer.get_available_filters(configuracion_reporte) response_data = {'data': data, 'available_filters': available_filters, 'available_columns': available_columns} return Response(response_data, status=status.HTTP_200_OK) except Exception as e: @@ -122,7 +131,10 @@ class DynamicTableAPIView(BasePermissionAPIView): # Extraer la configuración, o si no fue enviada asignamos la predeterminada configuracion = self.get_configuracion_reporte(request) - serializer = DynamicTable(instance=configuracion) + if self.dynamic_form_exist: + serializer = DynamicTableDynamicForm(instance=configuracion,model_class=self.model_class) + else: + serializer = DynamicTable(instance=configuracion,model_class=self.model_class) if self.columns == "__all__": self.columns = list(serializer.get_available_columns(configuracion).keys()) @@ -291,4 +303,4 @@ class Exportar_CSV(BasePermissionAPIView): # exportamos los datos response = reporte.export_to_csv_and_zip(data, uid) - return response + return response \ No newline at end of file diff --git a/cosiap_api/solicitudes/views.py b/cosiap_api/solicitudes/views.py index 6cecdef..4c3dd0f 100644 --- a/cosiap_api/solicitudes/views.py +++ b/cosiap_api/solicitudes/views.py @@ -36,6 +36,7 @@ class SolicitudAPIView(DynamicTableAPIView): } } non_editable_fields = ["status"] + dynamic_form_exist = True class HistorialAPIVIew(BasePermissionAPIView): -- GitLab From ab4215325f286f203e3c89baa9c8022b8ab0de79 Mon Sep 17 00:00:00 2001 From: AdalbertoCV <34152734@uaz.edu.mx> Date: Tue, 20 Aug 2024 21:01:46 -0600 Subject: [PATCH 2/3] Exportacion de reportes arreglada --- cosiap_api/dynamic_tables/DynamicTable.py | 107 ++++++++++++++-------- cosiap_api/dynamic_tables/views.py | 24 +++-- cosiap_api/solicitudes/urls.py | 1 + 3 files changed, 86 insertions(+), 46 deletions(-) diff --git a/cosiap_api/dynamic_tables/DynamicTable.py b/cosiap_api/dynamic_tables/DynamicTable.py index 958047a..7fd5eab 100644 --- a/cosiap_api/dynamic_tables/DynamicTable.py +++ b/cosiap_api/dynamic_tables/DynamicTable.py @@ -9,6 +9,7 @@ from .models import DynamicTableReport from django.db import models from collections import defaultdict from django.db.models import ForeignKey, ManyToManyField, OneToOneField, ManyToOneRel, FileField, ImageField +from solicitudes.models import Solicitud import re from django.core.exceptions import ValidationError, FieldDoesNotExist import json @@ -576,46 +577,74 @@ class DynamicTable(serializers.ModelSerializer): return overall_success - def export_to_csv_and_zip(self, data, uid): + def export_to_csv_and_zip(self, data=None, solicitud_id=None): """ Exporta los datos a un CSV y los archivos asociados a una estructura de directorios, y luego empaqueta todo en un archivo zip. + + Parámetros: + - data: Los datos a exportar. No se espera si se proporciona un solicitud_id. + - uid: Identificador único para el archivo zip. + - solicitud_id: ID de la solicitud específica a exportar. Si se proporciona, se exporta solo esa solicitud. """ # Configuramos los directorios correspondientes - temp_dir = os.path.join(settings.BASE_DIR, 'temp_export', uid) + temp_dir = os.path.join(settings.BASE_DIR, 'temp_export') os.makedirs(temp_dir, exist_ok=True) files_dir = os.path.join(temp_dir, 'archivos') os.makedirs(files_dir, exist_ok=True) csv_file_path = os.path.join(temp_dir, 'reporte.csv') - # Creamos el archivo CSV - with open(csv_file_path, mode='w', newline='', encoding='utf-8') as csvfile: - fieldnames = self.get_fieldnames(data) - writer = csv.DictWriter(csvfile, fieldnames=fieldnames) - writer.writeheader() - + if solicitud_id: + solicitud = Solicitud.objects.get(id=solicitud_id) + data = self.retrieve_instance_data(solicitud) - solicitudes_por_curp = {} - for item in data: - solicitante_curp = item.get('solicitante__curp') - if solicitante_curp: - solicitud_n = item.get('solicitud_n') - if solicitante_curp not in solicitudes_por_curp: - curp_dir = os.path.join(files_dir, f'solicitud_{solicitante_curp}') - os.makedirs(curp_dir, exist_ok=True) - solicitudes_por_curp[solicitante_curp] = curp_dir - - curp_dir = solicitudes_por_curp[solicitante_curp] - solicitud_dir = os.path.join(curp_dir, f'solicitud_{solicitud_n}') - os.makedirs(solicitud_dir, exist_ok=True) - - respuestas_dir = os.path.join(solicitud_dir, 'respuestas') - os.makedirs(respuestas_dir, exist_ok=True) - self.handle_files(item, solicitud_dir) - self.handle_responses(solicitud_n, respuestas_dir) - else: - self.handle_files(item, files_dir) - writer.writerow(item) + with open(csv_file_path, mode='w', newline='', encoding='utf-8') as csvfile: + fieldnames = self.get_fieldnames(data) + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + + print(data) + + solicitante = data.get('solicitante') + solicitante_curp = solicitante.get('curp') + id_solicitud = data.get('id') + curp_dir = os.path.join(files_dir, f'solicitud_{solicitante_curp}') + os.makedirs(curp_dir, exist_ok=True) + solicitud_dir = os.path.join(curp_dir, f'solicitud_{id_solicitud}') + os.makedirs(solicitud_dir, exist_ok=True) + + respuestas_dir = os.path.join(solicitud_dir, 'respuestas') + os.makedirs(respuestas_dir, exist_ok=True) + self.handle_files(data, solicitud_dir) + self.handle_responses(id_solicitud, respuestas_dir) + writer.writerow(data) + else: + with open(csv_file_path, mode='w', newline='', encoding='utf-8') as csvfile: + fieldnames = self.get_fieldnames(data) + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + + solicitudes_por_curp = {} + for item in data: + solicitante_curp = item.get('solicitante__curp') + if solicitante_curp: + id_solicitud = item.get('id') + if solicitante_curp not in solicitudes_por_curp: + curp_dir = os.path.join(files_dir, f'solicitud_{solicitante_curp}') + os.makedirs(curp_dir, exist_ok=True) + solicitudes_por_curp[solicitante_curp] = curp_dir + + curp_dir = solicitudes_por_curp[solicitante_curp] + solicitud_dir = os.path.join(curp_dir, f'solicitud_{id_solicitud}') + os.makedirs(solicitud_dir, exist_ok=True) + + respuestas_dir = os.path.join(solicitud_dir, 'respuestas') + os.makedirs(respuestas_dir, exist_ok=True) + self.handle_files(item, solicitud_dir) + self.handle_responses(id_solicitud, respuestas_dir) + else: + self.handle_files(item, files_dir) + writer.writerow(item) # Creamos un archivo zip zip_buffer = io.BytesIO() @@ -633,22 +662,28 @@ class DynamicTable(serializers.ModelSerializer): zip_buffer.seek(0) response = HttpResponse(zip_buffer, content_type='application/zip') - response['Content-Disposition'] = f'attachment; filename="reporte_{uid}.zip"' - - # Limpiamos directorio temporal + response['Content-Disposition'] = f'attachment; filename="reporte.zip"' shutil.rmtree(temp_dir) - return response + def get_fieldnames(self, data): """ Devuelve los nombres de los campos que se usarán en el CSV. + Maneja tanto listas de diccionarios como un solo diccionario. """ if not data: return [] - first_item = data[0] + # Verifica si 'data' es una lista de diccionarios + if isinstance(data, list): + first_item = data[0] + elif isinstance(data, dict): + first_item = data + else: + raise ValueError("El formato de los datos no es compatible") + return list(first_item.keys()) @@ -682,12 +717,12 @@ class DynamicTable(serializers.ModelSerializer): continue - def handle_responses(self, solicitud_n, respuestas_dir): + def handle_responses(self, id_solicitud, respuestas_dir): """ Maneja la extracción de respuestas relacionadas con la solicitud y las guarda en el directorio correspondiente. """ # Filtrar las respuestas por solicitud - responses = RDocumento.objects.filter(registro_id=solicitud_n) + responses = RDocumento.objects.filter(registro_seccion_id=id_solicitud) for response in responses: file_path = os.path.join(respuestas_dir, os.path.basename(response.valor.name)) diff --git a/cosiap_api/dynamic_tables/views.py b/cosiap_api/dynamic_tables/views.py index 20ed81f..83fc1a5 100644 --- a/cosiap_api/dynamic_tables/views.py +++ b/cosiap_api/dynamic_tables/views.py @@ -13,6 +13,7 @@ from django.core.exceptions import ValidationError import json from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode +from solicitudes.models import Solicitud class DynamicTableAPIView(BasePermissionAPIView): @@ -271,7 +272,7 @@ class Exportar_CSV(BasePermissionAPIView): APIView para manejar la exportación de los datos según una configuración de reporte. ''' permission_classes_list = [IsAuthenticated, es_admin] - model_name = None + model_class = Solicitud def get_configuracion_reporte(self, request): ''' @@ -295,12 +296,15 @@ class Exportar_CSV(BasePermissionAPIView): Método get para obtener el archivo zip con todos los documentos solicitados. ''' - configuracion = self.get_configuracion_reporte(request) - reporte = DynamicTable(instance=configuracion) - data = reporte.get_data(configuracion) - # creamos un UID encriptado para la creación del ZIP único del usuario. - uid = urlsafe_base64_encode(force_bytes(request.user.pk)) - - # exportamos los datos - response = reporte.export_to_csv_and_zip(data, uid) - return response \ No newline at end of file + if 'pk' in kwargs: + reporte = DynamicTableDynamicForm(model_class=self.model_class) + solicitud_id = kwargs['pk'] + response = reporte.export_to_csv_and_zip(solicitud_id=solicitud_id) + return response + else: + configuracion = self.get_configuracion_reporte(request) + reporte = DynamicTableDynamicForm(instance=configuracion, model_class=self.model_class) + data = reporte.get_data(configuracion) + + response = reporte.export_to_csv_and_zip(data) + return response \ No newline at end of file diff --git a/cosiap_api/solicitudes/urls.py b/cosiap_api/solicitudes/urls.py index c69c3a8..c2eb518 100644 --- a/cosiap_api/solicitudes/urls.py +++ b/cosiap_api/solicitudes/urls.py @@ -13,4 +13,5 @@ urlpatterns = [ path('reportes/', views.ReportesSolicitudesAPIView.as_view(), name='reportes_solicitudes'), path('reportes//', views.ReportesSolicitudesAPIView.as_view(), name='reportes_solicitudes_pk'), path('reportes/exportar/', Exportar_CSV.as_view(), name='exportar_reportes'), + path('reportes/exportar//', Exportar_CSV.as_view(), name='exportar_reportes_pk'), ] \ No newline at end of file -- GitLab From 98443da8a55ebb4d523cbda4dd5d89d0695f9c81 Mon Sep 17 00:00:00 2001 From: AdalbertoCV <34152734@uaz.edu.mx> Date: Wed, 21 Aug 2024 11:49:26 -0600 Subject: [PATCH 3/3] Exportar una solicitud por pk --- cosiap_api/dynamic_tables/DynamicTable.py | 32 ++++++++++++++++++----- cosiap_api/dynamic_tables/views.py | 2 +- cosiap_api/solicitudes/urls.py | 5 ++-- cosiap_api/solicitudes/views.py | 8 ++++++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/cosiap_api/dynamic_tables/DynamicTable.py b/cosiap_api/dynamic_tables/DynamicTable.py index 7fd5eab..8c9f73c 100644 --- a/cosiap_api/dynamic_tables/DynamicTable.py +++ b/cosiap_api/dynamic_tables/DynamicTable.py @@ -596,17 +596,15 @@ class DynamicTable(serializers.ModelSerializer): if solicitud_id: solicitud = Solicitud.objects.get(id=solicitud_id) - data = self.retrieve_instance_data(solicitud) + data_nested = self.retrieve_instance_data(solicitud) + data = self.flatten_dict(data_nested) with open(csv_file_path, mode='w', newline='', encoding='utf-8') as csvfile: fieldnames = self.get_fieldnames(data) writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() - print(data) - - solicitante = data.get('solicitante') - solicitante_curp = solicitante.get('curp') + solicitante_curp = data.get('solicitante__curp') id_solicitud = data.get('id') curp_dir = os.path.join(files_dir, f'solicitud_{solicitante_curp}') os.makedirs(curp_dir, exist_ok=True) @@ -623,8 +621,8 @@ class DynamicTable(serializers.ModelSerializer): fieldnames = self.get_fieldnames(data) writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() - solicitudes_por_curp = {} + for item in data: solicitante_curp = item.get('solicitante__curp') if solicitante_curp: @@ -692,9 +690,14 @@ class DynamicTable(serializers.ModelSerializer): Maneja los archivos adjuntos, los guarda en el directorio correspondiente basado en el nombre de la columna. """ for key, value in item.items(): + print(key, '-', value) if value and isinstance(value, str) and value.endswith(('.png', '.jpg', '.jpeg', '.pdf')): # Detectar directorio basado en la primera parte del nombre de la columna column_dir = key.split('__')[0] + + if value.startswith('/media/'): + value = value[len('/media/'):] + if column_dir == 'modalidad': continue @@ -735,3 +738,20 @@ class DynamicTable(serializers.ModelSerializer): response.archivo = os.path.join('archivos', 'respuestas', os.path.basename(response.valor.name)) response.save() + + def flatten_dict(self,d, parent_key='', sep='__'): + ''' + Método para convertir un diccionario anidado a un dichionario plano + + param:d: diccionario anidado a convertir + param:parent_key: parámetro para marcar los keys padres durante el ciclo + param:sep: separador de columna_relacion + ''' + items = [] + for k, v in d.items(): + new_key = f"{parent_key}{sep}{k}" if parent_key else k + if isinstance(v, dict): + items.extend(self.flatten_dict(v, new_key, sep=sep).items()) + else: + items.append((new_key, v)) + return dict(items) \ No newline at end of file diff --git a/cosiap_api/dynamic_tables/views.py b/cosiap_api/dynamic_tables/views.py index 83fc1a5..0079336 100644 --- a/cosiap_api/dynamic_tables/views.py +++ b/cosiap_api/dynamic_tables/views.py @@ -272,7 +272,7 @@ class Exportar_CSV(BasePermissionAPIView): APIView para manejar la exportación de los datos según una configuración de reporte. ''' permission_classes_list = [IsAuthenticated, es_admin] - model_class = Solicitud + model_class = None def get_configuracion_reporte(self, request): ''' diff --git a/cosiap_api/solicitudes/urls.py b/cosiap_api/solicitudes/urls.py index c2eb518..adeb962 100644 --- a/cosiap_api/solicitudes/urls.py +++ b/cosiap_api/solicitudes/urls.py @@ -1,7 +1,6 @@ from . import views from django.urls import path from django.contrib.auth import views as auth_views -from dynamic_tables.views import Exportar_CSV app_name = 'solicitudes' @@ -12,6 +11,6 @@ urlpatterns = [ path('historial//', views.HistorialAPIVIew.as_view(), name='historial_pk'), path('reportes/', views.ReportesSolicitudesAPIView.as_view(), name='reportes_solicitudes'), path('reportes//', views.ReportesSolicitudesAPIView.as_view(), name='reportes_solicitudes_pk'), - path('reportes/exportar/', Exportar_CSV.as_view(), name='exportar_reportes'), - path('reportes/exportar//', Exportar_CSV.as_view(), name='exportar_reportes_pk'), + path('reportes/exportar/', views.ExportarReporteSolicitudes.as_view(), name='exportar_reportes'), + path('reportes/exportar//', views.ExportarReporteSolicitudes.as_view(), name='exportar_reportes_pk'), ] \ No newline at end of file diff --git a/cosiap_api/solicitudes/views.py b/cosiap_api/solicitudes/views.py index 4c3dd0f..5819342 100644 --- a/cosiap_api/solicitudes/views.py +++ b/cosiap_api/solicitudes/views.py @@ -19,6 +19,7 @@ from dynamic_tables.views import ReporteAPIView from rest_framework.permissions import AllowAny from dynamic_tables.models import DynamicTableReport from dynamic_tables.DynamicTable import DynamicTable +from dynamic_tables.views import Exportar_CSV class SolicitudAPIView(DynamicTableAPIView): ''' @@ -95,3 +96,10 @@ class ReportesSolicitudesAPIView(ReporteAPIView): return Response(serializer.data) +class ExportarReporteSolicitudes(Exportar_CSV): + ''' + Clase que hereda de Exportar_CSV de tablas dinámicas + especializando la exportación para solicitudes. + ''' + model_class = Solicitud + -- GitLab