Saltar a contenido

🛠 Unidad ISS-04 · Modelo Client — capa 🛠 CONSTRUIR

🧠 Comprender este bloque → · ✅ GATE de la unidad

Capa Página Para qué
🧠 Aprender Guía de estudio comprender, explicar y relacionar
🛠 Construir esta página ejecutar, programar y verificar
✅ GATE Condiciones de cierre condición para pasar al bloque siguiente

Esta es la guía ejecutable. El cuerpo de abajo es el ISS técnico verbatim: comandos, rutas, versiones, verificaciones y criterios, sin simplificar.


ISS-04 — Modelo Client

Objetivo

Persistir compradores con el diccionario de clients.

Requisitos

  • ISS-03 superado.
  • Un solo TextChoices para active / inactive.

Construcción

RecordStatus ya está en apps/common/status.py desde el ISS-03. El modelo abstracto es un archivo nuevo. No es una app: no entra en INSTALLED_APPS y no genera migración propia. TimeStampedModel aporta created_at y updated_at. StoreLabModel añade status con default inactive y el CheckConstraint reutilizable. Las apps de negocio heredan esta clase; por eso la tabla clients sí tiene esas columnas.

cat > apps/common/models.py <<'EOF'
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,
        )
EOF

apps/client/models.py lo creó startapp vacío. Se reescribe entero: el comentario inicial no se conserva. Client hereda timestamps y estado. name exige al menos 2 caracteres. address, phone y email pueden ir vacíos. email es único y save() lo guarda en minúsculas. db_table = "clients" fija el nombre físico. El constraint clients_status_valid cabe en 30 caracteres, el límite histórico de Oracle.

cat > apps/client/models.py <<'EOF'
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)
EOF

La migración la escribe la CLI:

python manage.py makemigrations client
python manage.py migrate

El serializer, en el ISS-07, convierte "" en None para que la unicidad del email no choque con cadenas vacías. La prueba HTTP llega en el ISS-08. Aquí basta crear un cliente en el shell y ver status, created_at y el rechazo de un email repetido.

Explicación

  • MinLengthValidator(2) vive en el modelo: la API y el admin comparten el rango 2–150.
  • El default inactive se hereda de StoreLabModel.
  • save() guarda el email en minúsculas.
  • El CheckConstraint de estado es portable y su nombre cabe en 30 caracteres.
clients
  id, name, address?, phone?, email?, status, created_at, updated_at

Criterios de aceptación

  • AC-04-01: la tabla física es clients.
  • AC-04-02: sin status en el alta, el valor es inactive.
  • AC-04-03: created_at y updated_at se generan.
  • AC-04-04: el email duplicado se rechaza.
  • AC-04-05: un nombre de un carácter se rechaza.

Verificación

ClientApiTests en PostgreSQL, MySQL y SQL Server.

Evidencias

  • EVI-04-01: migración client.0001_initial aplicada.
  • EVI-04-02: tests de cliente PASS.

GATE

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

✅ GATE de la unidad ISS-04 — este bloque no añade ningún criterio nuevo.

Las condiciones de cierre son las de esta misma página:

Con el GATE en verde queda habilitado el bloque siguiente de la ruta.

Navegación de la ruta: ← ISS-04 · 🧠 Aprender · ↑ Ruta Django · → ISS-05 · 🧠 Aprender