Gestión de Entidades en la DPE (parte 3)
Published: 2024-04-24 04:06:34

Este tutorial cubre los siguientes puntos:

- Definición de plantilla con formulario para registro de Entidades.
- Definición de URLs y vistas.
- Configuración de archivos estáticos.

**Paso 1: Definición de URLs, vista y plantilla inicial**

- Crea un archivo urls.py en la aplicación "entidades": Una vez creado el archivo define la URL para la página de inicio y asóciala con una vista llamada "home" que renderice la plantilla correspondiente. 

```
from django.urls import path
from entidades import views

urlpatterns = [
    path('', views.home),
]
```

- Incluir las urls de la aplicación dentro del proyecto:
En el archivo gestor_entidades/urls.py:

```
from django.urls import path, include

urlpatterns = [
    # Otras urls
    path('', include('entidades.urls'))
]
```

- Definición de la vista: En el archivo views.py de la aplicación, define la vista home que renderizará la plantilla de inicio.

```
from django.shortcuts import render

def home(request):
    return render(request, 'index.html')
```

- Creación de la plantilla: Crea la plantilla "index.html" en el directorio /entidades/templates.

```
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Formulario de Registro de Entidades de la DPE</title>
</head>
<body> 
</body>   
</html>
```

**Paso 2: Configuración de archivos estáticos**

- Configurar el directorio estático: En el proyecto, asegúrate de tener configurado el directorio estático en tu archivo settings.py. Esto es necesario para que Django pueda servir los archivos estáticos correctamente.

```
STATIC_URL = 'static/'
STATICFILES_DIRS = (BASE_DIR / 'static',)
```

- Colocar el archivo favicon en el directorio estático: Mueve el archivo favicon (favicon.ico) al directorio estático de tu proyecto 
(static/img).

- Referenciar el favicon en la plantilla: Abre la plantilla "index.html" y agrega el enlace al favicon en la sección <head>.
Es importante agregar al inicio de la plantilla la directiva `{% load static %}`

```
{% load static %}

<link rel="shortcut icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}">
```

- Agregrar estáticos de Bootstrap y JQuery vía CDN: En la plantilla "index.html" agregar los enlaces al CDN de Bootstrap CSS en el bloque `<head>` y Bootstrap JS, así como JQuery en el bloque `<body>`

```
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

```

- Crear el archivo "form-entidad.js en el directorio estático: 
(static/js).

- Agregrar estáticos de JS en la plantilla "index.html" en el bloque `<body>`


```
<script src="{% static 'js/form-entidad.js' %}"></script>
```

**Paso 3: Incluir formulario de Registro de Entidad**

A continuación, vamos a incluir el formulario con todos los campos del modelo Entidad:

- Agregar dentro del código de la plantilla "index.html" el siguiente bloque:

```
<div class="container my-3">
    <h1 class="text-center">Registro de Entidad</h1>        
    <form class="my-2 row g-3" id="form-entidad">            
        <div class="col-md-6">
            <label for="input-ruc" class="form-label fw-bold">RUC</label>
            <input type="text" class="form-control" id="input-ruc" name="ruc">
        </div>
        <div class="col-md-6">
            <label for="input-nombre" class="form-label fw-bold">Nombre</label>
            <input type="text" class="form-control" id="input-nombre" name="nombre">
        </div>
        <div class="col-md-12">
            <label class="form-label fw-bold">Tipo de Organización</label>                
            {% for tipo_org in tipos_organizaciones %}
                <div class="form-check">
                    <input class="form-check-input" type="radio" name="tipo_organizacion" value="{{tipo_org.id}}" id="input-tipo-org-{{tipo_org.id}}">
                    <label class="form-check-label" for="input-tipo-org-{{tipo_org.id}}">{{tipo_org.nombre}}
                    </label>
                </div>
            {% endfor %}
        </div>
        <div class="col-md-6">
            <label for="select-tipo-entidad" class="form-label fw-bold">Tipo de Entidad</label>
            <select class="form-select" id="select-tipo-entidad" name="tipo_entidad">
                <option value="" selected disabled>Seleccione...</option>
                {% for tipo_ent in tipos_entidades %}
                    <option value="{{tipo_ent.id}}">{{tipo_ent.nombre}}</option>
                {% endfor %}
            </select>
        </div>
        <div class="col-md-6">
            <label for="select-funcion" class="form-label fw-bold">Función</label>
            <select class="form-select" id="select-funcion" name="funcion">
                <option value="" selected disabled>Seleccione...</option>
                {% for funcion in funciones %}
                    <option value="{{funcion.id}}">{{funcion.nombre}}</option>
                {% endfor %}
            </select>
        </div>
        <div class="col-md-12">
            <label class="form-label fw-bold">Control SNAP (Secretaría Nacional de la Administración Pública/Secretaría Técnica de Transparencia de Gestión):)</label>
            <div class="form-check">
                <input class="form-check-input" type="radio" name="control_snap" value="1" id="input-control-snap-1">
                <label class="form-check-label" for="input-control-snap-1">SI</label>
            </div>
            <div class="form-check">
                <input class="form-check-input" type="radio" name="control_snap" value="0" id="input-control-snap-0">
                <label class="form-check-label" for="input-control-snap-0">NO</label>
            </div>
        </div>
        <div class="col-md-6">
            <label for="select-ambito-accion" class="form-label fw-bold">Ámbito de Acción</label>
            <select class="form-select" id="select-ambito-accion" name="ambito_accion">
                <option value="" selected disabled>Seleccione...</option>
                {% for ambito_accion in ambitos_accion %}
                    <option value="{{ambito_accion.id}}">{{ambito_accion.nombre}}</option>
                {% endfor %}
            </select>
        </div>
        <h4 class="text-center">Ubicación de la Entidad</h4>
        <hr>
        <div class="col-md-6">
            <label for="select-zonal" class="form-label fw-bold">Zonal</label>
            <select class="form-select" id="select-zonal" name="zonal">
                <option value="" selected disabled>Seleccione...</option>
                {% for zonal in zonales %}
                    <option value="{{zonal.id}}">{{zonal.nombre}}</option>
                {% endfor %}
            </select>
        </div>
        <div class="col-md-6">
            <label for="select-provincia" class="form-label fw-bold">Provincia</label>
            <select class="form-select" id="select-provincia" name="provincia">
                <option value="" selected disabled>Seleccione...</option>
                {% for provincia in provincias %}
                    <option value="{{provincia.id}}">{{provincia.nombre}}</option>
                {% endfor %}
            </select>
        </div>
        <div class="col-md-6">
            <label for="select-canton" class="form-label fw-bold">Cantón</label>
            <select class="form-select" id="select-canton" name="canton">
            </select>
        </div>
        <div class="col-md-6">
            <label for="select-parroquia" class="form-label fw-bold">Parroquia</label>
            <select class="form-select" id="select-parroquia" name="parroquia">
            </select>
        </div>
        <div class="col-md-12">
            <label for="input-direccion" class="form-label fw-bold">Dirección</label>
            <input type="text" class="form-control" id="input-direccion" name="direccion">
        </div>
        <div class="col-md-4">
            <label for="input-telefono" class="form-label fw-bold">Teféfono</label>
            <input type="text" class="form-control" id="input-telefono" name="telefono">
        </div>
        <div class="col-md-4">
            <label for="input-correo-institucional" class="form-label fw-bold">Correo institucional</label>
            <input type="email" class="form-control" id="input-correo-institucional" name="correo_institucional">
        </div>
        <div class="col-md-4">
            <label for="select-tipo-gad" class="form-label fw-bold">Tipo de GAD</label>
            <select class="form-select" id="select-tipo-gad" name="tipo_gad">
                <option value="" selected disabled>Seleccione...</option>
                {% for tipo_gad in tipos_gad %}
                    <option value="{{tipo_gad.id}}">{{tipo_gad.nombre}}</option>
                {% endfor %}
            </select>
        </div>
        <h4 class="text-center">Datos legales de la Entidad</h4>
        <hr>
        <div class="col-md-12">
            <label for="area-base-normativa" class="form-label fw-bold">Base Normativa</label>
            <textarea class="form-control" id="area-base-normativa" name="base_normativa" rows="10"></textarea>
        </div>
        <div class="col-md-6">
            <label for="area-base-normativa" class="form-label fw-bold">Fecha Publicación Base Legal</label>                
            <input type="date" class="form-control" id="input-fecha-pub-base-legal" name="fecha_publicacion_base_legal" min="1900-01-01" />
        </div>
        <div class="col-md-6">
            <label for="input-num-registro-oficial" class="form-label fw-bold">No. Registro Oficial</label>
            <input type="text" class="form-control" id="input-num-registro-oficial" name="num_registro_oficial">
        </div>
        <div class="col-md-12">
            <label for="area-nota-aclaracion" class="form-label fw-bold">Nota de aclaración alguna particularidad</label>
            <textarea class="form-control" id="area-nota-aclaracion" name="nota_aclaracion" rows="3"></textarea>
        </div>
        <div class="col-md-12">
            <label for="input-nombres-max-autoridad" class="form-label fw-bold">Nombres de la máx. autoridad</label>
            <input type="text" class="form-control" id="input-nombres-max-autoridad" name="nombres_maxima_autoridad">
        </div>
        <h4 class="text-center">Datos del responsable de ingresar informe anual</h4>
        <hr>
        <div class="col-md-12">
            <label for="input-nombres-responsable" class="form-label fw-bold">Nombres del responsable</label>
            <input type="text" class="form-control" id="input-nombres-responsable" name="nombres_responsable">
        </div>
        <div class="col-md-6">
            <label for="input-correo-responsable" class="form-label fw-bold">Correo</label>
            <input type="email" class="form-control" id="input-correo-responsable" name="correo_responsable">
        </div>
        <div class="col-md-4">
            <label for="input-telef-responsable" class="form-label fw-bold">Teléfono</label>
            <input type="text" class="form-control" id="input-telef-responsable" name="telefono_responsable">
        </div>
        <div class="col-md-2">
            <label for="input-ext-telef-responsable" class="form-label fw-bold">Ext. Teléfono</label>
            <input type="text" class="form-control" id="input-ext-telef-responsable" name="extension_telef_responsable">
        </div>
        <h4 class="text-center">Adjuntos</h4>
        <hr>
        <div class="col-md-12">
            <label for="input-file-ordenanza" class="form-label fw-bold">Ordenanza (pdf)</label>
            <input class="form-control" type="file" id="input-file-ordenanza" name="file_ordenanza">
        </div>
        <div class="col-md-12">
            <label for="input-file-reg-oficial" class="form-label fw-bold">Registro Oficial (pdf)</label>
            <input class="form-control" type="file" id="input-file-reg-oficial" name="file_registro_oficial">
        </div>
        <div class="col-md-12">
            <label for="input-file-ruc" class="form-label fw-bold">RUC (pdf)</label>
            <input class="form-control" type="file" id="input-file-ruc" name="file_ruc">
        </div>
        <div class="col-md-12">
            <button type="submit" class="btn btn-primary">Registrar</button>
            <button type="reset" class="btn btn-secondary">Cancelar</button>
        </div>
    </form>
</div>
```

- En la vista home incluir el envío de los datos requeridos por la plantilla, tales como: tipos_organizaciones, tipos_entidades, funciones, ambitos_accion, zonales, etc.:

```
def home(request):
    tipos_organizaciones = TipoOrganizacion.objects.all()
    tipos_entidades = TipoEntidad.objects.all()
    funciones = Funcion.objects.all()
    ambitos_accion = AmbitoAccion.objects.all()
    zonales = Zonal.objects.all()
    provincias = Provincia.objects.all()
    tipos_gad = TipoGad.objects.all()
    return render(request, 'index.html',{'tipos_organizaciones': tipos_organizaciones,
                                          'tipos_entidades': tipos_entidades,
                                          'funciones': funciones,
                                          'ambitos_accion': ambitos_accion,
                                          'zonales': zonales,
                                          'provincias': provincias,
                                          'tipos_gad': tipos_gad,
                                        })
```

- Para tener la posibilidad de consultar los cantones y parroquias de acuerdo a la provincia y cantón seleccionado por el usuario debemos crear las urls y funciones de vista que permitan obtener los datos en formato JSON:

Creamos las urls:

```
urlpatterns = [
    # Otras urls
    path('provincias/<int:provincia_id>/cantones/', views.get_cantones),
    path('cantones/<int:canton_id>/parroquias/', views.get_parroquias),
]
```

Creamos las funciones de vista:

```
def get_cantones(request, provincia_id):   
    cantones = Canton.objects.filter(provincia__id=provincia_id).values('id', 'nombre')
    cantones_dict_list = list(cantones)  # Convierte los objetos QuerySet en una lista de diccionarios
    return JsonResponse(cantones_dict_list, safe=False)


def get_parroquias(request, canton_id):   
    parroquias = Parroquia.objects.filter(canton__id=canton_id).values('id', 'nombre')
    parroquias_dict_list = list(parroquias)  # Convierte los objetos QuerySet en una lista de diccionarios
    return JsonResponse(parroquias_dict_list, safe=False)
```

Consumimos las rutas usando JQuery:

```
$(document).ready(function() {
    $('#select-provincia').change(function() {
        let provincia_id = $(this).val();
        $.ajax({
            url: '/provincias/' + provincia_id + '/cantones/',
            type: 'GET',
            success: function(data) {
                $('#select-canton').empty();
                $('#select-parroquia').empty();
                $.each(data, function(index, canton) {
                    $('#select-canton').append($('<option>', {
                        value: canton.id,
                        text: canton.nombre
                    }));
                });
            },
            error: function(xhr, textStatus, errorThrown) {
                console.error('Error al obtener los cantones:', errorThrown);                
            }
        });
    });

    $('#select-canton').change(function() {
        let canton_id = $(this).val();
        $.ajax({
            url: '/cantones/' + canton_id + '/parroquias/',
            type: 'GET',
            success: function(data) {
                $('#select-parroquia').empty();                
                $.each(data, function(index, parroquia) {
                    $('#select-parroquia').append($('<option>', {
                        value: parroquia.id,
                        text: parroquia.nombre
                    }));
                });
            },
            error: function(xhr, textStatus, errorThrown) {
                console.error('Error al obtener las parroquias:', errorThrown);                
            }
        });
    });
});
```