🛠 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
TextChoicesparaactive/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:
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
inactivese hereda deStoreLabModel. save()guarda el email en minúsculas.- El
CheckConstraintde estado es portable y su nombre cabe en 30 caracteres.
Criterios de aceptación
- AC-04-01: la tabla física es
clients. - AC-04-02: sin
statusen el alta, el valor esinactive. - AC-04-03:
created_atyupdated_atse 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_initialaplicada. - 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:
- 📋 Criterios de aceptación → Criterios de aceptación
- ✅ GATE → GATE
- 🔎 Verificación → Verificación
- 🧠 Autoevaluación → Evaluación del cuaderno
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