Saltar a contenido

📚 Unidad ISS-04 · Modelo Client — capa 🧠 APRENDER

🛠 Construir este bloque → · ✅ Condiciones de cierre (GATE) · 📝 Evaluación

Capa Página Para qué
🧠 Aprender esta página comprender, explicar y relacionar
🛠 Construir Modelo Client ejecutar, programar y verificar
✅ GATE Cierre de la unidad condición para pasar al bloque siguiente

Mapa de correspondencias. Cada fila enlaza el mismo tema en las dos capas; los enlaces apuntan a secciones reales del material.

Tema 🧠 Aprender (esta página) 🛠 Construir (ISS técnico)
Objetivo 1. Objetivos Estructurales y Requisitos Previos del ISS-04 Objetivo
Recorrido 6. Secuencia de Comandos CLI y Ciclo de Migración Construcción
Cierre 9. Matriz de Criterios de Aceptación, Verificación y Tabla GATE Criterios de aceptación · GATE
Evaluación 10. Cuestionario Formativo y Preguntas para Defensa Oral Técnica GATE

🖥 Presentación del ISS

Presentación de la unidad. Diapositivas de ISS-04 — Modelo Client (15 diapositivas). Se visualiza aquí, dentro del sitio.

⛶ Ver presentación completa ⬇ Archivo editable (.pptx)

15 diapositivas · se visualiza dentro del sitio.

🎬 Video explicativo

Recorrido audiovisual de la unidad. El video recorre el ISS técnico de ISS-04 — Modelo Client, bloque por bloque.

7:44 min · narración en español · subtítulos activables desde el reproductor.

Infografía

Infografía de la unidad

Mapa conceptual

  • Objetivo
  • Persistir compradores con el diccionario de clients
  • Requisitos
  • ISS-03 superado
  • Un solo TextChoices para active y inactive
  • Construcción
  • Modelo abstracto (apps/common/models.py)
    • TimeStampedModel: created_at y updated_at
    • StoreLabModel: status con default inactive y check constraint
  • Modelo Client (apps/client/models.py)
    • name: CharField(150) con MinLengthValidator(2)
    • address: CharField(255) opcional
    • phone: CharField(30) opcional
    • email: EmailField(150) único y opcional
    • db_table: clients
    • ordering: [name, id]
    • CheckConstraint: clients_status_valid (30 caracteres para Oracle)
    • save(): normaliza email en minúsculas
  • Migraciones CLI
    • makemigrations client
    • migrate
  • Explicación
  • MinLengthValidator(2): compartido entre API y admin
  • Default inactive heredado de StoreLabModel
  • Normalización de email a minúsculas en save()
  • CheckConstraint portable con límite de 30 caracteres
  • Criterios de Aceptación
  • AC-04-01: Tabla física clients
  • AC-04-02: Default inactive sin status en alta
  • AC-04-03: Timestamps created_at y updated_at
  • AC-04-04: Rechazo de email duplicado
  • AC-04-05: Rechazo de nombre de un carácter
  • Verificación y Evidencias
  • Verificación: ClientApiTests en PostgreSQL, MySQL y SQL Server
  • EVI-04-01: Migración client.0001_initial aplicada
  • EVI-04-02: Tests de cliente PASS

Guía de Estudio Pedagógica: ISS-04 — Modelo Client y Arquitectura de Modelos Base Abstractos


1. Objetivos Estructurales y Requisitos Previos del ISS-04

Dentro de la hoja de ruta de ingeniería del proyecto StoreLab, la unidad ISS-04 representa un hito fundamental en la transición desde la capa de seguridad e identidad (ISS-03) hacia la construcción del núcleo de dominio del negocio. Habiendo consolidado la autenticación de usuarios sobre la entidad security.User, resulta estratégicamente vital persistir el dominio de los compradores (clients) de manera aislada y desacoplada. Esta separación arquitectónica garantiza que las credenciales de acceso e infraestructura de sesión no se contaminen con los atributos comerciales y transaccionales del cliente, manteniendo un modelo de dominio enfocado estrictamente en las reglas operativas de la compraventa.

Para abordar la implementación del ISS-04 de forma satisfactoria, es indispensable haber cumplido rigurosamente con los siguientes requisitos técnicos previos: 1. Superación previa del ISS-03: Haber generado y aplicado de manera limpia la migración inicial de la aplicación de seguridad (security.0001_initial) y tener configurado explícitamente AUTH_USER_MODEL = "security.User" en el archivo de configuración global (config/settings/__init__.py). 2. Existencia de la enumeración RecordStatus: Disponer del paquete transversal apps/common/status.py, donde se encuentra declarada la clase RecordStatus(models.TextChoices) con sus miembros ACTIVE = "active", "Active" e INACTIVE = "inactive", "Inactive".

El diseño global de StoreLab impone como regla de arquitectura centralizar el estado activo e inactivo de todas las entidades en este único enumerado TextChoices. Esta decisión minimiza la dispersión semántica, elimina la proliferación de literales de texto (magic strings) desperdigados en el código y permite declarar restricciones relacionales homogéneas a nivel de motor de base de datos. Comprender cómo Django ORM traduce estas estructuras de alto nivel hacia esquemas relacionales físicos es el fundamento conceptual indispensable para abordar la persistencia del dominio del cliente.


2. Conceptos Esenciales y Vocabulario Técnico Fundamental

El dominio del vocabulario técnico de Django ORM no debe entenderse como la memorización pasiva de sintaxis, sino como la base semántica necesaria para la construcción de software mantenible, robusto y portable a través de sistemas distribuidos multidialecto (PostgreSQL, MySQL, SQL Server y Oracle).

Matriz Conceptual de Persistencia y Estructura ORM

Concepto Técnico Definición en Django / ORM Propósito en StoreLab / Impacto Sistémico
abstract = True Meta-opción de clase que indica a Django ORM que la clase no debe generar una tabla física independiente en la base de datos relacional. Permite definir clases base reutilizables (TimeStampedModel, StoreLabModel) cuyos campos y validaciones se heredan directamente en las tablas de las entidades concretas.
TimeStampedModel Clase base abstracta que encapsula los campos de auditoría temporal created_at y updated_at. Garantiza una trazabilidad cronológica homogénea a nivel de infraestructura para todas las tablas del sistema, sin duplicar código de modelos.
StoreLabModel Clase base abstracta derivada de TimeStampedModel que integra la gestión de estado (status) y la fábrica del constraint relacional. Unifica el estado inactivo por defecto para los registros de negocio y estandariza la regla de validación de integridad a nivel de motor SQL.
MinLengthValidator Validador declarativo de Django (django.core.validators) que verifica la longitud mínima de caracteres de una cadena de texto. Aplica la regla de negocio directamente en el ORM y los formularios, impidiendo la persistencia de nombres de clientes de un solo carácter.
CheckConstraint Restricción declarativa de base de datos (models.CheckConstraint) que proyecta una cláusula SQL CHECK explícita en la tabla física. Garantiza a nivel de motor relacional que el valor insertado en la columna status pertenezca estrictamente a los valores permitidos en RecordStatus.values.
db_table Opción de la clase interna Meta que especifica de forma explícita la nomenclatura física de la tabla SQL. Desacopla el nombre de la clase Python de la tabla relacional, imponiendo nombres en plural, minúsculas y sin prefijos implícitos (clients).
Compatibilidad con Oracle Restricción técnica asociada al límite histórico de 30 bytes/caracteres para nombres de objetos (tablas, índices, restricciones y triggers). Obliga a parametrizar el nombre del CheckConstraint (ej. "clients_status_valid", 20 caracteres) para prevenir fallos catastróficos de DDL en Oracle.

Nota sobre la compatibilidad con Oracle: Es crítico comprender que las configuraciones tradicionales y por defecto de Oracle Database imponen un límite estricto de 30 bytes para identificadores de objetos. Si un constraint en Django supera este umbral (por ejemplo, "clients_record_status_valid_check_constraint"), la migración fallará al ejecutarse sobre dicho motor, impidiendo la interoperabilidad multidialecto de StoreLab.

Estos conceptos convergen directamente en la organización física del repositorio, determinando la jerarquía de directorios y la separación de responsabilidades entre paquetes.


3. Arquitectura de Paquetes y Principio de Abstracción en apps/common vs. apps/client

La arquitectura de StoreLab aplica una separación estricta entre los componentes de infraestructura reutilizables (apps/common) y las entidades ligadas al dominio específico del negocio (apps/client). Esta estructuración modular previene el acoplamiento indeseado y evita que la lógica comercial contamine los bloques de utilidades transversales.

Estructura del Directorio del Proyecto

storelab/
├── apps/
│   ├── common/
│   │   ├── __init__.py
│   │   ├── models.py      # Contiene TimeStampedModel y StoreLabModel (abstractos)
│   │   └── status.py      # Contiene el enumerado RecordStatus (TextChoices)
│   │                      # [NOTA: apps/common NO posee directorio migrations/]
│   └── client/
│       ├── __init__.py
│       ├── apps.py        # Configuración de la app (name="apps.client", label="client")
│       ├── migrations/    # Directorio de migraciones concretas del dominio
│       │   └── __init__.py
│       └── models.py      # Contiene el modelo concreto Client que hereda de StoreLabModel

Naturaleza de apps/common y la Marcación abstract = True

A diferencia de las aplicaciones de negocio, apps/common no se registra en INSTALLED_APPS dentro de config/settings/__init__.py, ni se crea utilizando el comando startapp de la CLI de Django. Se trata de un paquete Python ordinario diseñado exclusivamente para alojar clases abstractas y utilitarios del sistema.

¿Por qué apps/common no genera sus propias tablas físicas en la base de datos?

La respuesta técnica radica en el uso del flag abstract = True dentro de la subclase Meta de cada modelo definido en apps/common/models.py: 1. Instrucción al ORM: Al marcar un modelo como abstracto, Django ORM omite la generación de sentencias DDL CREATE TABLE common_timestampedmodel o CREATE TABLE common_storelabmodel. 2. Aplanamiento de Esquema (Flattening): Los campos, metadatos y métodos definidos en la clase base se incorporan y "aplanan" directamente dentro del esquema físico de los modelos concretos que heredan de ella (como Client). 3. Eficiencia en Consultas: Se evita el severo impacto en rendimiento provocado por la herencia de tabla concreta (Multi-table inheritance), la cual exige realizar operaciones JOIN implícitas entre la tabla padre y la tabla hija en cada consulta SQL.

Para el archivo apps/client/models.py —el cual sí pertenece a una aplicación registrada en INSTALLED_APPS—, el proceso de implementación exige una reescritura total del archivo. Se debe eliminar por completo el comentario predeterminado generado por la CLI (# Create your models here.), garantizando una base de código limpia y profesional.

Esta clara distinción entre paquetes abstractos de infraestructura y modelos concretos de dominio nos permite abordar el análisis línea por línea de la implementación de apps/common/models.py.


4. Desglose Semántico por Bloques del Archivo apps/common/models.py

La construcción de clases base abstractas aplica rigurosamente el principio DRY (Don't Repeat Yourself), eliminando la duplicación de código en la definición de auditoría temporal, estado y restricciones relacionales.

Código Completo de apps/common/models.py

from django.db import models

from apps.common.status import RecordStatus


class TimeStampedModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True


class StoreLabModel(TimeStampedModel):
    status = models.CharField(
        max_length=8,
        choices=RecordStatus.choices,
        default=RecordStatus.INACTIVE,
    )

    class Meta:
        abstract = True

    @classmethod
    def status_constraint(cls, name):
        return models.CheckConstraint(
            condition=models.Q(status__in=RecordStatus.values),
            name=name,
        )

Análisis Semántico por Bloques

Bloque 1: Importaciones y Dependencias Base

  • from django.db import models: Importa el módulo fundamental del ORM de Django para acceder a los tipos de datos de columnas, metadatos y constructores de restricciones.
  • from apps.common.status import RecordStatus: Carga la enumeración centralizada de estados, garantizando que el modelo base interactúe directamente con ACTIVE e INACTIVE.

Bloque 2: TimeStampedModel (Auditoría Temporal)

  • created_at = models.DateTimeField(auto_now_add=True): Registra automáticamente la fecha y hora exactas (con zona horaria) en las que el objeto se inserta por primera vez en la base de datos. Este valor es inmutable y no vuelve a modificarse en actualizaciones posteriores.
  • updated_at = models.DateTimeField(auto_now=True): Se actualiza automáticamente con la marca de tiempo corriente cada vez que se invoca el método save() sobre la instancia.
  • class Meta: abstract = True: Declara expresamente el carácter abstracto de la clase, instruyendo al ORM a no crear una tabla física para TimeStampedModel.

Bloque 3: StoreLabModel (Gestión de Estado y Restricción Estandarizada)

  • Herencia de TimeStampedModel: Adquiere automáticamente la auditoría temporal (created_at y updated_at).
  • status = models.CharField(...):
  • max_length=8: Ancho de columna optimizado para almacenar la cadena "inactive" (8 caracteres) o "active" (6 caracteres).
  • choices=RecordStatus.choices: Enlaza la columna con las tuplas legibles del enumerado.
  • default=RecordStatus.INACTIVE: Aplica la regla de negocio donde todo nuevo registro de la plataforma nace en estado inactivo por defecto.
  • class Meta: abstract = True: Mantiene el comportamiento abstracto en la jerarquía de herencia.
  • @classmethod def status_constraint(cls, name):
  • Método de clase diseñado como fábrica de restricciones relacionales CheckConstraint.
  • Evalúa condition=models.Q(status__in=RecordStatus.values), garantizando que la base de datos SQL rechace cualquier valor distinto a "active" o "inactive".
  • Encapsula la creación del constraint permitiendo parametrizar el argumento name en cada entidad hija, asegurando la adaptabilidad del identificador a los límites de longitud de cada motor SQL.

Una vez definida esta infraestructura abstracta en apps/common/models.py, procede su herencia concreta en la entidad del dominio del cliente.


5. Desglose Semántico por Bloques del Modelo de Dominio apps/client/models.py

El modelo Client encapsula la información de los compradores del sistema StoreLab, extendiendo la infraestructura de auditoría y estado provista por StoreLabModel.

Código Completo de apps/client/models.py

from django.core.validators import MinLengthValidator
from django.db import models

from apps.common.models import StoreLabModel


class Client(StoreLabModel):
    name = models.CharField(max_length=150, validators=[MinLengthValidator(2)])
    address = models.CharField(max_length=255, null=True, blank=True)
    phone = models.CharField(max_length=30, null=True, blank=True)
    email = models.EmailField(max_length=150, null=True, blank=True, unique=True)

    class Meta:
        db_table = "clients"
        verbose_name = "cliente"
        verbose_name_plural = "clientes"
        ordering = ["name", "id"]
        constraints = [StoreLabModel.status_constraint("clients_status_valid")]

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if self.email:
            self.email = self.email.strip().lower()
        super().save(*args, **kwargs)

Análisis Detallado por Bloques Funcionales

1. Importaciones y Validadores

  • from django.core.validators import MinLengthValidator: Importa el validador encargado de verificar la longitud mínima de caracteres. Su colocación directa en la definición del campo garantiza que la validación ocurra transversalmente en el ORM, formularios e inspecciones del modelo, rechazando nombres de un solo carácter.

2. Campos de la Clase Client

  • Herencia de StoreLabModel: Absorbe los campos created_at, updated_at y status (con valor por defecto "inactive").
  • name: Campo obligatorio (NOT NULL) de tipo CharField con longitud máxima de 150 caracteres y validación declarativa de mínimo 2 caracteres (MinLengthValidator(2)).
  • address: Campo opcional para la dirección (max_length=255, null=True, blank=True).
  • phone: Campo opcional para el teléfono de contacto (max_length=30, null=True, blank=True).
  • email: Campo opcional (EmailField, max_length=150, null=True, blank=True) configurado con restricción de unicidad (unique=True).
Profundización Pedagógica: Comportamiento SQL de null=True, blank=True, unique=True

Existe una sutileza crítica a nivel de motores de bases de datos relacionales con el campo email. En SQL, la restricción UNIQUE permite la coexistencia de múltiples valores NULL (None en Python), ya que conceptualmente NULL representa la ausencia de valor y dos nulos no son iguales entre sí. Sin embargo, si por un error de diseño o falta de saneamiento se inserta una cadena vacía "" en una columna UNIQUE, el motor relacional almacenará el literal "". Al intentar insertar un segundo cliente con email vacío "", el motor SQL lanzará una violación de unicidad (IntegrityError), dado que "" == "" sí constituye un duplicado. Para resolver esta discrepancia entre los formularios web (que tienden a enviar cadenas vacías) y la base de datos relacional, el serializador de cliente en el ISS-07 (ClientSerializer.validate_email) convierte explícitamente cualquier cadena vacía o con espacios en blanco en None, asegurando que la base de datos reciba NULL y previniendo colisiones de unicidad.

3. Configuración Meta

  • db_table = "clients": Sobreescribe la convención por defecto de Django (client_client), fijando el nombre físico de la tabla en plural y minúsculas.
  • verbose_name y verbose_name_plural: Definen la traducción legible de la entidad ("cliente" / "clientes").
  • ordering = ["name", "id"]: Establece el ordenamiento predeterminado para las consultas del ORM (alfabético por nombre y desempate por ID).
  • constraints = [StoreLabModel.status_constraint("clients_status_valid")]: Invoca el método de clase abstracto para registrar el CheckConstraint. La cadena "clients_status_valid" posee exactamente 20 caracteres, respetando holgadamente el límite de 30 bytes/caracteres de Oracle.

4. Métodos de Clase (__str__ y save())

  • def __str__(self): Retorna self.name, proporcionando una representación en texto clara para logs, consolas interactivas y paneles de administración.
  • def save(self, *args, **kwargs): Normaliza el correo electrónico antes de ejecutar la persistencia física. Si self.email contiene un valor, le aplica .strip().lower() para remover espacios en los extremos y convertir la cadena a minúsculas, garantizando consistencia antes de invocar a super().save(*args, **kwargs).

Una vez codificado el modelo de dominio, se debe proceder con la secuencia CLI de migraciones para materializar el esquema relacional en la base de datos.


6. Secuencia de Comandos CLI y Ciclo de Migración

Las migraciones en Django operan como un libro contable atómico y versionado que traduce las modificaciones declaradas en el código Python hacia instrucciones DDL (Data Definition Language) sobre la base de datos relacional.

Comandos de Ejecución CLI

  1. Generación de la Notación de Cambio:
    python manage.py makemigrations client
    
  2. Aplicación DDL en la Base de Datos:
    python manage.py migrate
    

Mecánica Interna del Ciclo de Migración

Código Python (apps/client/models.py)
       │
       ▼  python manage.py makemigrations client
El ORM inspecciona el modelo Client.
Puesto que apps/common NO está en INSTALLED_APPS, Django analiza
la herencia de StoreLabModel, extrae y aplana sus campos abstractos
(status, created_at, updated_at) y los combina con los campos de Client.
       │
       ▼  Escribe el archivo declarativo:
apps/client/migrations/0001_initial.py
       │
       ▼  python manage.py migrate
Lectura de 0001_initial.py y traducción a sentencias SQL DDL.
Ejecución atómica en el motor activo (PostgreSQL, MySQL, SQL Server, etc.).
       │
       ▼  Proyección Física:
Tabla "clients" creada con sus columnas, índices y restricción CHECK.

Durante la ejecución de makemigrations client, Django identifica que Client hereda de StoreLabModel. Al verificar que StoreLabModel es abstracto (abstract = True), Django proyecta directamente los campos status, created_at y updated_at dentro del archivo apps/client/migrations/0001_initial.py. Posteriormente, migrate lee estas instrucciones y ejecuta las sentencias SQL correspondientes para crear físicamente la tabla clients.


7. Esquema Físico Resultante de la Tabla clients

La inspección de la proyección relacional física permite confirmar que los atributos, nulabilidades, valores por defecto y restricciones declarados en el ORM se reflejen correctamente en el motor SQL.

Estructura Relacional de la Tabla clients

Columna Tipo de Dato SQL Nulabilidad / Restricciones Origen / Herencia
id BIGINT / BIGSERIAL NOT NULL, PRIMARY KEY, AUTO_INCREMENT Generado automáticamente por Django (BigAutoField).
name VARCHAR(150) NOT NULL Declarado en Client (con MinLengthValidator(2) en Python).
address VARCHAR(255) NULL (Permite valores nulos) Declarado en Client (null=True, blank=True).
phone VARCHAR(30) NULL (Permite valores nulos) Declarado en Client (null=True, blank=True).
email VARCHAR(150) NULL, UNIQUE Declarado en Client (null=True, blank=True, unique=True).
status VARCHAR(8) NOT NULL, DEFAULT 'inactive', CHECK (status IN ('active', 'inactive')) Heredado de StoreLabModel (restricción nombrada "clients_status_valid").
created_at TIMESTAMP WITH TIME ZONE NOT NULL Heredado de TimeStampedModel (auto_now_add=True).
updated_at TIMESTAMP WITH TIME ZONE NOT NULL Heredado de TimeStampedModel (auto_now=True).

Como se observa en el esquema, la columna status proyecta explícitamente el valor por defecto SQL 'inactive' (correspondiente a RecordStatus.INACTIVE) y queda protegida relacionalmente mediante el CheckConstraint explícito denominado "clients_status_valid".


8. Diagnóstico, Prevención y Análisis de Errores Frecuentes

El diagnóstico anticipado de fallos es una competencia de ingeniería indispensable para prevenir regresiones en entornos de producción y garantizar la estabilidad del esquema multidialecto.

Matriz de Diagnóstico de Errores en ISS-04

Error / Omisión Efecto / Causa Raíz Impacto en Producción / Base de Datos Solución Correctiva
Omitir abstract = True en las clases de apps/common/models.py. Django tratará a las clases base como modelos de tabla concreta. Se crean tablas físicas innecesarias (common_timestampedmodel) y Django ejecuta JOINs relacionales implícitos en cada consulta de clientes, degradando severamente el rendimiento. Incluir abstract = True en la subclase Meta de TimeStampedModel y StoreLabModel dentro de apps/common/models.py.
Omisión de MinLengthValidator(2) en el campo name. El ORM permite persistir nombres de un solo carácter (ej. "A"). Contaminación de la base de datos con registros basura o no válidos, evadiendo la regla de negocio de disponer de un nombre comercial real. Agregar validators=[MinLengthValidator(2)] en la definición del campo name en apps/client/models.py.
Olvidar la normalización .strip().lower() en el método save(). Correos como " Juan@Example.com " se almacenan sin sanear. Falla la restricción unique=True ante variaciones de mayúsculas o espacios, permitiendo la existencia de duplicados lógicos en la base de datos. Implementar el bloque if self.email: self.email = self.email.strip().lower() dentro de save() en apps/client/models.py.
Exceder el límite de 30 caracteres en el CheckConstraint. Nombrar la restricción con identificadores largos (ej. "clients_record_status_valid_check_constraint"). La ejecución DDL falla catastróficamente en motores Oracle debido al límite histórico de 30 bytes para nombres de objetos y restricciones. Utilizar identificadores concisos que no superen los 30 caracteres, tales como "clients_status_valid" (20 caracteres).

9. Matriz de Criterios de Aceptación, Verificación y Tabla GATE

La metodología de desarrollo de StoreLab exige la validación rigurosa de cada Criterio de Aceptación (AC) mediante evidencias tangibles antes de autorizar el avance hacia las siguientes unidades.

Mapeo de Criterios de Aceptación y Evidencias

  • AC-04-01: La tabla física en la base de datos relacional se denomina explícitamente clients.
  • AC-04-02: Si se registra un cliente sin especificar el valor de estado, el sistema le asigna automáticamente el valor "inactive".
  • AC-04-03: Las marcas de tiempo created_at y updated_at se generan automáticamente durante la creación del registro.
  • AC-04-04: La inserción de un correo electrónico duplicado es rechazada por el sistema (HTTP 400 / IntegrityError).
  • AC-04-05: El intento de registrar un cliente con un nombre de un solo carácter es rechazado (HTTP 400 / ValidationError).

Las evidencias de soporte corresponden a: * EVI-04-01: Aplicación de la migración client.0001_initial confirmada en el motor de base de datos relacional. * EVI-04-02: Ejecución exitosa en verde (PASS) de la suite de pruebas unitarias y de integración para el cliente (python manage.py test apps.client).

Tabla GATE — ISS-04

AC Verificación Evidencia Resultado
AC-04-01 db_table EVI-04-01 PASS
AC-04-02 POST sin status EVI-04-02 PASS
AC-04-03 timestamps EVI-04-02 PASS
AC-04-04 email duplicado = 400 EVI-04-02 PASS
AC-04-05 nombre corto = 400 EVI-04-02 PASS

La superación de la Tabla GATE certifica que la capa de persistencia de clientes cumple con los estándares de ingeniería exigidos y habilita el paso a la fase de defensa técnica.


10. Cuestionario Formativo y Preguntas para Defensa Oral Técnica

La evaluación oral técnica mide la capacidad del ingeniero para justificar las decisiones de diseño arquitectónico y el comportamiento interno de Django ORM, trascendiendo la mera memoria operacional de comandos CLI.

Cuestionario de Defensa Oral

Pregunta 1

¿Por qué se utiliza herencia abstracta (abstract = True) en apps/common en lugar de herencia de tabla concreta o modelos Proxy? * Justificación Técnica Profunda: La herencia de tabla concreta (Multi-table inheritance) genera una tabla física independiente para el modelo padre y establece relaciones OneToOneField automáticas con los modelos hijos. Esto fuerza a la base de datos a realizar operaciones JOIN en cada consulta de lectura para reconstruir los campos de auditoría y estado, degradando el rendimiento del motor relacional. Por su parte, los modelos Proxy no permiten agregar campos nuevos, sirviendo únicamente para alterar comportamientos Python sobre tablas existentes. La herencia abstracta (abstract = True) permite compartir la declaración de columnas (status, created_at, updated_at) y validaciones en código Python, proyectándolas directamente dentro de la tabla física clients en una estructura plana sin costo de uniones relacionales. * Enfoque Pedagógico: Mide la capacidad del estudiante para tomar decisiones de modelado ORM basadas en la optimización del rendimiento relacional y el diseño de esquemas eficientes.

Pregunta 2

¿Por qué la validación de longitud mínima (MinLengthValidator) debe colocarse a nivel de modelo y no únicamente en los serializadores o la API REST? * Justificación Técnica Profunda: Restringir los validadores a la capa de API REST (serializadores de DRF) deja desprotegidas otras vías de ingesta de datos en el sistema, como scripts de carga masiva, comandos de gestión CLI, tareas asíncronas de fondo o el panel de administración (django.contrib.admin). Al declarar MinLengthValidator(2) directamente en el campo del modelo (models.CharField), la regla de negocio queda centralizada dentro del ciclo de vida del ORM (a través de full_clean()), asegurando que ningún componente interno o externo pueda violar la integridad del atributo name. * Enfoque Pedagógico: Evalúa la adopción del principio de "Defensa en Profundidad" y la centralización de las invariantes de dominio dentro del modelo de datos.

Pregunta 3

¿Cuál es el impacto exacto de ejecutar .strip().lower() en el método save() del modelo en lugar de confiar en el saneamiento del cliente/frontend? * Justificación Técnica Profunda: El frontend es un entorno no seguro que puede ser eludido o manipulado fácilmente mediante clientes HTTP (cURL, Postman) o scripts maliciosos. Si un correo como " Client@StoreLab.com " ingresa sin sanear, la restricción unique=True en bases de datos relacionales puede fallar de forma imprevista debido a las reglas de cotejo (collation) del motor o al tratamiento de espacios, permitiendo la coexistencia de correos duplicados lógicos (ej. "client@storelab.com" y "Client@StoreLab.com"). Ejecutar la normalización en el método save() del modelo garantiza que, sin importar la fuente del dato, la cadena se limpie de espacios y se convierta a minúsculas antes de la sentencia INSERT/UPDATE SQL, garantizando la unicidad estricta en la columna física. * Enfoque Pedagógico: Comprueba la conciencia sobre seguridad defensiva en el desarrollo de software y la preservación de la consistencia de datos en el servidor.

Pregunta 4

¿Por qué es crítico limitar los nombres de las restricciones (CheckConstraint) a un máximo de 30 caracteres en proyectos multidialecto como StoreLab? * Justificación Técnica Profunda: Aunque motores modernos como PostgreSQL o MySQL soportan identificadores de restricciones de hasta 63 o 64 caracteres, motores relacionales como Oracle (en versiones corporativas de amplio uso) imponen un límite estricto de 30 bytes/caracteres para nombres de objetos (tablas, columnas, índices, triggers y constraints). Si un modelo define un nombre de restricción extenso como "clients_record_status_valid_check_constraint" (43 caracteres), la aplicación funcionará correctamente en PostgreSQL, pero fallará catastróficamente al ejecutar las migraciones en Oracle. Fijar el nombre en "clients_status_valid" (20 caracteres) asegura la compatibilidad e interoperabilidad absoluta del código en arquitecturas multidialecto. * Enfoque Pedagógico: Mide la preparación técnica del ingeniero para diseñar aplicaciones empresariales capaces de ejecutarse de forma transparente sobre múltiples motores relacionales.

Pregunta 5

¿Cómo interactúa el valor por defecto RecordStatus.INACTIVE de StoreLabModel con el ciclo de vida de los registros en el sistema? * Justificación Técnica Profunda: La adopción de RecordStatus.INACTIVE como valor por defecto aplica el principio de "Negación por Defecto" (Deny by Default) sobre el ciclo de vida de las entidades. Un registro recién insertado no debe considerarse automáticamente activo o disponible para operaciones comerciales o transaccionales hasta que cumpla con los flujos de validación o aprobación requeridos por el negocio. Al heredar este comportamiento desde StoreLabModel, se garantiza que todas las entidades del dominio nazcan en un estado seguro e inactivo, evitando que registros incompletos participen prematuramente en los procesos de la plataforma. * Enfoque Pedagógico: Evalúa la comprensión de los patrones de diseño defensivo aplicados a la persistencia y al ciclo de vida de los datos de negocio.


Navegación de la ruta: ← ISS-03 · 🛠 Construir · ↑ Ruta Django · → ISS-04 · 🛠 Construir