Registro de Entidades en la DPE
Published: 2024-04-18 23:18:05

Este tutorial cubre los siguientes puntos:

- Definición de modelos.
- Configuración de la conexión a una base de datos PostgreSQL.
- Configuración del administrador de Django para gestionar los modelos.

**Paso 1: Definición de Modelos**

- Dentro del directorio de la aplicación "entidades", primero crea un directorio llamado "models".

- Dentro del directorio "models", crea un archivo especial `__init__.py` para convertir el directorio en un paquete de Python.

- Luego, dentro del paquete "models", crea el archivo Python: "catalogs.py"

La estructura de directorios debería verse así:

```
entidades/
├── __init__.py
├── admin.py
├── apps.py
├── migrations/
│   └── ...
├── models/
│   ├── __init__.py
│   ├── catalogs.py
├── tests.py
└── views.py
```

- Abre el archivo "catalogs.py" y pega el código de los modelos tipo catálogo dentro de él.

```

# entidades/models/catalogs.py
from django.db import models

class TipoOrganizacion(models.Model):
    nombre = models.CharField(max_length=250)
    fecha_registro = models.DateTimeField(auto_now_add=True)
    fecha_ult_act = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return f'{self.nombre} ({self.id})'

    class Meta:
        db_table = 'ent_tipos_organizacion'
        verbose_name = 'Tipo de Organización'
        verbose_name_plural = 'Tipos de Organización'
        

class TipoEntidad(models.Model):
    nombre = models.CharField(max_length=75)
    fecha_registro = models.DateTimeField(auto_now_add=True)
    fecha_ult_act = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return f'{self.nombre} ({self.id})'

    class Meta:
        db_table = 'ent_tipos_entidad'
        verbose_name = 'Tipo de Entidad'
        verbose_name_plural = 'Tipos de Entidad'
        
        
class Funcion(models.Model):
    nombre = models.CharField(max_length=50)
    fecha_registro = models.DateTimeField(auto_now_add=True)
    fecha_ult_act = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return f'{self.nombre} ({self.id})'

    class Meta:
        db_table = 'ent_tipos_funcion'
        verbose_name = 'Tipo de Función'
        verbose_name_plural = 'Tipos de Función'
        
        
class AmbitoAccion(models.Model):
    nombre = models.CharField(max_length=25)
    fecha_registro = models.DateTimeField(auto_now_add=True)
    fecha_ult_act = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return f'{self.nombre} ({self.id})'

    class Meta:
        db_table = 'ent_ambitos_accion'
        verbose_name = 'Ámbito de Acción'
        verbose_name_plural = 'Ámbitos de Acción'
        
        
class Zonal(models.Model):
    nombre = models.CharField(max_length=25)
    fecha_registro = models.DateTimeField(auto_now_add=True)
    fecha_ult_act = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return f'{self.nombre} ({self.id})'

    class Meta:
        db_table = 'ent_zonales'
        verbose_name = 'Zonal'
        verbose_name_plural = 'Zonales'
        

class Provincia(models.Model):
    nombre = models.CharField(max_length=50)
    fecha_registro = models.DateTimeField(auto_now_add=True)
    fecha_ult_act = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return f'{self.nombre} ({self.id})'

    class Meta:
        db_table = 'ent_provincias'
        verbose_name = 'Provincia'
        verbose_name_plural = 'Provincias'
        

class Canton(models.Model):
    nombre = models.CharField(max_length=100)
    provincia = models.ForeignKey(Provincia, on_delete=models.CASCADE)
    fecha_registro = models.DateTimeField(auto_now_add=True)
    fecha_ult_act = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return f'{self.nombre} ({self.id})'

    class Meta:
        db_table = 'ent_cantones'
        verbose_name = 'Cantón'
        verbose_name_plural = 'Cantones'
        

class Parroquia(models.Model):
    nombre = models.CharField(max_length=100)
    canton = models.ForeignKey(Canton, on_delete=models.CASCADE)
    fecha_registro = models.DateTimeField(auto_now_add=True)
    fecha_ult_act = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return f'{self.nombre} ({self.id})'

    class Meta:
        db_table = 'ent_parroquias'
        verbose_name = 'Parroquia'
        verbose_name_plural = 'Parroquias'
        
        
class TipoGad(models.Model):
    nombre = models.CharField(max_length=50)
    fecha_registro = models.DateTimeField(auto_now_add=True)
    fecha_ult_act = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return f'{self.nombre} ({self.id})'

    class Meta:
        db_table = 'ent_tipos_gad'
        verbose_name = 'Tipo de GAD'
        verbose_name_plural = 'Tipo de GAD'
```

- En el módulo `models/__init__.py` incluye la importación de los modelos creados:

```
from .catalogs import *
```

**Paso 2: Configuración de la Conexión a PostgreSQL**

En el archivo `gestor_entidades/settings.py`, asegúrate de configurar la conexión a la base de datos PostgreSQL. Reemplaza la sección DATABASES con lo siguiente:

```
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'nombre_basededatos',
        'USER': 'usuario_basededatos',
        'PASSWORD': 'contraseña',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}
```
Asegúrate de reemplazar 'nombre_basededatos', 'usuario_basededatos', y 'contraseña' con los detalles correctos de tu base de datos PostgreSQL.

Adicionalmente se necesita instalar el controlador psycopg2 en tu entorno virtual. Puedes hacerlo ejecutando el siguiente comando en tu terminal:

```poetry add psycopg2-binary```


**Paso 3: Creación y Ejecución de Migraciones**

- Ejecuta el siguiente comando para crear las migraciones iniciales:

```poetry run python manage.py makemigrations```

Este comando buscará cualquier cambio en tus modelos y generará archivos de migración en el directorio migrations/ de cada aplicación de tu proyecto.

Después de crear las migraciones, ejecuta el siguiente comando para aplicar las migraciones a la base de datos:

```poetry run python manage.py migrate```

Este comando ejecutará todas las migraciones pendientes y actualizará la base de datos de acuerdo con los modelos definidos.

Si tienes algún problema con la migración o necesitas revertir los cambios, puedes usar el siguiente comando para deshacer la última migración aplicada:

```poetry run python manage.py migrate <nombre_aplicacion> zero```

Reemplaza <nombre_aplicacion> con el nombre de la aplicación donde deseas deshacer la migración. También puedes usar zero en lugar de un nombre de migración específico para deshacer todas las migraciones de esa aplicación.

**Paso 4: Configuración del Administrador**

En el archivo `entidades/admin.py`, registra tus modelos para que puedan ser gestionados a través del administrador de Django:

```
from django.contrib import admin
from entidades.models import *

admin.site.site_header = 'Administrador del Catastro de Entidades'

@admin.register(TipoOrganizacion)
class TipoOrganizacionAdmin(admin.ModelAdmin):
    list_display = ('id', 'nombre', 'fecha_registro', 'fecha_ult_act')
    
@admin.register(TipoEntidad)
class TipoEntidadAdmin(admin.ModelAdmin):
    list_display = ('id', 'nombre', 'fecha_registro', 'fecha_ult_act')

@admin.register(Funcion)
class FuncionAdmin(admin.ModelAdmin):
    list_display = ('id', 'nombre', 'fecha_registro', 'fecha_ult_act')

@admin.register(AmbitoAccion)
class AmbitoAccionAdmin(admin.ModelAdmin):
    list_display = ('id', 'nombre', 'fecha_registro', 'fecha_ult_act')

@admin.register(Zonal)
class ZonalAdmin(admin.ModelAdmin):
    list_display = ('id', 'nombre', 'fecha_registro', 'fecha_ult_act')

@admin.register(Provincia)
class ProvinciaAdmin(admin.ModelAdmin):
    list_display = ('id', 'nombre', 'fecha_registro', 'fecha_ult_act')

@admin.register(Canton)
class CantonAdmin(admin.ModelAdmin):
    list_display = ('id', 'nombre', 'provincia', 'fecha_registro', 'fecha_ult_act')

@admin.register(Parroquia)
class ParroquiaAdmin(admin.ModelAdmin):
    list_display = ('id', 'nombre', 'canton', 'fecha_registro', 'fecha_ult_act')

@admin.register(TipoGad)
class TipoGadAdmin(admin.ModelAdmin):
    list_display = ('id', 'nombre', 'fecha_registro', 'fecha_ult_act')

```

¡Y eso es todo! Ahora puedes acceder al administrador de Django en http://localhost:8000/admin

Recuerda crear un superusuario ejecutando:

```poetry run python manage.py createsuperuser```

Y finalmente, para ejecutar el servidor de desarrollo de Django, usa el siguiente comando:

`poetry run python manage.py runserver`

**Paso 5: Carga de datos**

- Descarga los datos iniciales desde el siguiente enlace: [Datos iniciales](https://assets-publicos-clases-prog.s3.amazonaws.com/data1-gestor-entidades.zip)

- Una vez descargado el archivo zip, descomprímelo y copia la carpeta `data/` en la raíz del directorio del proyecto.

La estructura de directorios debería verse así:

```
gestor_entidades/
data/
├── provincias.csv
entidades/
manage.py
poetry.lock
pyproject.toml
```

A continuación, crea una carpeta `scripts/` en la raíz del directorio del proyecto. Puedes crear esta carpeta manualmente o hacerlo ejecutando el siguiente comando en tu terminal:

```mkdir scripts```

Vamos a hacer que la carpeta `scripts/` sea un paquete de Python y luego crearemos los scripts para importar los datos al modelo de Provincia mediante los archivos csv descargados.

- Dentro del directorio "scripts", crea el archivo especial 
`__init__.py` para convertir el directorio en un paquete.
- Luego, dentro del paquete "scripts", crea el archivo Python: `provincia_feeder.py`.

- Abre el archivo `provincia_feeder.py` y pega el siguiente código:

```
import csv
from entidades.models import Provincia

def feed_provincias():
    Provincia.objects.all().delete()
    
    with open('data/provincias.csv') as csv_file:
        csv_dict_reader = csv.DictReader(csv_file, delimiter=';')
        for item in csv_dict_reader:
            provincia= Provincia(id=item['id'], nombre=item['nombre'])
            provincia.save()
            print(f'Provincia creada: {provincia}')
        

def run():
    feed_provincias()

```

Para poder ejecutar los scripts de carga de datos debemos instalar el paquete "django-extensions". Debemos hacerlo ejecutando en la terminal del comando:

```poetry add django-extensions```

"django-extensions" es un complemento para el framework Django y por ello debemos agregarlo en la configuración de INSTALLED_APPS del proyecto. Abre el archivo `gestor_entidades/settings.py` y busca la lista INSTALLED_APPS. Añade la aplicación al final de esta lista. Debería verse así:

```
INSTALLED_APPS = [
    ...
    'django_extensions'
]
```
Una vez concluidos estos pasos procederemos a ejecutar el script para cargar los datos iniciales. En la terminal vamos a ejecutar:

```poetry run python manage.py runscript provincia_feeder```

Si todo va bien deberíamos tener cargados los registros de provincias en la base de datos PostgreSQL. Verifiquémoslo ejecutando el proyecto con:

```poetry run python manage.py runserver```

Y accede al administrador de Django en http://localhost:8000/admin.

Espero que este tutorial te haya sido útil.