Creación de Modelos
Los modelos hacen referencia a las tablas del diseño de su base de datos. Para este caso asumimos el siguiente diseño.

Estas tablas se agruparan en los siguientes modulos o aplicaciones:\ - Sale
- Product
Client
Antes de crear los modelos de la aplicación es necesario que configuremos nuestra base de datos.
Especificación de la base de datos
Primero se debe instalar las extensiones en Django que permiten comunicarse con los motores de base de datos.
MySQL
Postgresql
MS SQL Server y
Oracle
Las librerias serian:
# MS SQL
# python -m pip install mssql-django pyodbc
# POSTGRES
# python -m pip install psycopg2-binary
# MYSQL
# python -m pip install mysqlclient
# ORACLE
# python -m pip install cx_Oracle
Lo hacemos de la siguiente manera:




Recomendaciones:
Cada vez que se instala una libreria se debe actualizar el requierements.txt
Esto actualiza el archivo de librerias asi:

En caso que se genere algun error probar con la instalación de la siguiente manera:
Y luego intentar nuevamente
python3 -m pip install mysqlclient
Éste es también el punto donde normalmente especificarías la base de datos a utilizar en el proyecto --- tiene sentido usar la misma base datos para desarrollo y producción donde sea posible, para evitar diferencias menores en el comportamiento. Puedes encontrar información sobre las diferentes opciones de bases de datos en Databases (Django docs).
Para que se puedan realizar todas las conexiones a todos motores mencionados a las base de datos se realiza la siguiente configuracion en:
-
Un archivo .env en la carpeta raiz
-
La configuracion en settings.py
Primero creamos el archivo .env
# Database Engine Selection
# Options: mysql, postgresql, mssql, oracle
DATABASE_ENGINE=mysql
# MySQL Configuration
MYSQL_NAME=almacen_2025_iisem_django
MYSQL_USER=admin
MYSQL_PASSWORD=MiNiCo57**
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
# PostgreSQL Configuration
POSTGRES_NAME=almacen_2025_iisem_django
POSTGRES_USER=postgres
POSTGRES_PASSWORD=MiNiCo57**
POSTGRES_HOST=127.0.0.1
POSTGRES_PORT=5432
# MS SQL Server Configuration
MSSQL_NAME=almacen_2025_iisem_django
MSSQL_USER=sa
MSSQL_PASSWORD=MiNiCo57**
MSSQL_HOST=127.0.0.1
MSSQL_PORT=1433
# Oracle Configuration
ORACLE_NAME=almacendb_admin_django
ORACLE_USER=almacendb_admin_django
ORACLE_PASSWORD=MiNiCo57
ORACLE_HOST=127.0.0.1
ORACLE_PORT=1521
ORACLE_SID=XE
# MS SQL
# python -m pip install mssql-django pyodbc
# POSTGRES
# python -m pip install psycopg2-binary
# MYSQL
# python -m pip install mysqlclient
# ORACLE
# python -m pip install cx_Oracle
Luego configuramos settings.py
sitealmacen/sitealmacen/settings.py - Actualizar con el siguiente código.
Reemplazo
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
Por
# Get the selected database engine from environment
DATABASE_ENGINE = config('DATABASE_ENGINE', default='mysql')
# Database configurations
DATABASE_CONFIGS = {
'mysql': {
'ENGINE': 'django.db.backends.mysql',
'NAME': config('MYSQL_NAME'),
'USER': config('MYSQL_USER'),
'PASSWORD': config('MYSQL_PASSWORD'),
'HOST': config('MYSQL_HOST'),
'PORT': config('MYSQL_PORT'),
'OPTIONS': {
'charset': 'utf8mb4',
},
},
'postgresql': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('POSTGRES_NAME'),
'USER': config('POSTGRES_USER'),
'PASSWORD': config('POSTGRES_PASSWORD'),
'HOST': config('POSTGRES_HOST'),
'PORT': config('POSTGRES_PORT'),
},
'mssql': {
'ENGINE': 'mssql',
'NAME': config('MSSQL_NAME'),
'USER': config('MSSQL_USER'),
'PASSWORD': config('MSSQL_PASSWORD'),
'HOST': config('MSSQL_HOST'),
'PORT': config('MSSQL_PORT'),
'OPTIONS': {
'driver': 'ODBC Driver 17 for SQL Server',
},
},
'oracle': {
'ENGINE': 'django.db.backends.oracle',
'NAME': f"{config('ORACLE_HOST')}:{config('ORACLE_PORT')}/{config('ORACLE_SID', default='XE')}",
'USER': config('ORACLE_USER'),
'PASSWORD': config('ORACLE_PASSWORD'),
},
}
# Set the database configuration based on the selected engine
DATABASES = {
'default': DATABASE_CONFIGS.get(DATABASE_ENGINE, DATABASE_CONFIGS['mysql'])
}
Para generar las tablas respectivas debemos crear en Dbeaver las bases de datos que escribimos en el .env
Que para nuestro caso fueron:
MySQL
almacen_2025_iisem_django
Postgresql
almacen_2025_iisem_django
MS SQL Seerver
almacen_2025_iisem_django
Oracle
almacendb_admin_django
Ya podemos probar realizando las migraciones, sin aun haber realizado los modelos. Esto es debido a que Django ya trae unos modelos pre establecidos.
Para ello, migramos de la siguiente manera:
Es importante que para acceder a las variables de entorno instalar:
Y adicionalmente importarla en settings.py

En la ventana de terminal del proyecto en Visual Studio Code, recordemos que debe estar activa la unidad virtual y ubicados en la carpeta del proyecto sitealmacen. tal como se muestra.
(.venv) ubuntu@PortatlJQ:~/appsweb/clasesdlloweb/backdjango/2022iisem/sitealmacen$
Escribimos lo siguiente:
python3 manage.py makemigrations => Crea las migraciones
python3 manage.py migrate ==> Crea la base de datos físicamente, de acuerdo a las migraciones actuales.
Podemos probar en la terminar de Ubuntu, con el motor de MySQL abierto, para que nos muestre las tablas generadas en la base de datos que fueron creadas automáticamente, con la siguiente instrucción:
use almacen2022_mysql; ==> Para entrar a la base de datos
show tables; ==> Para mostrar las tablas de la base de datos.
Dando como resultado:
+-----------------------------+
| Tables_in_almacen2022_mysql |
+-----------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+-----------------------------+
10 rows in set (0.00 sec)
Código de los Modelos de Negocio
Aplicación Clientes
Los códigos de los modelos se realizan dentro de cada aplicación, que para este caso en particular se crearían en Apps/clientes/models.py de la siguiente manera:
En este caso tomaremos la tabla de clientes dentro de la aplicación correspondiente
Modelo de Client
from django.db import models
# Create your models here.
class Cliente(models.Model):
nombreCliente = models.CharField(max_length=100, help_text="Ingrese el Nombre del Cliente")
direccionCliente = models.CharField(max_length=100, help_text="Ingrese la Direccion del Cliente")
telefonoCliente = models.CharField(max_length=12, help_text="Ingrese el Telefono del Cliente")
correoCliente = models.EmailField(max_length=100, help_text="Ingrese el Correo del Cliente")
passwordCliente = models.CharField(max_length=100, help_text="Ingrese el Password del Cliente")
def __str__(self):
return self.nombreCliente
class Meta:
verbose_name = "cliente"
verbose_name_plural = "clientes"
Cada modelo obedece a una clase que hereda o extiende de la clase models.Model, la cual debemos importar.
Cada campo o atributo del modelo, para este caso Cliente posee Nombre, Tipo y Argumento de los campos.
Tipo de los Campos
El tipo del campo pueden ser (Numérico, Fecha, Boolean, entre otros). Para saber todos los tipos de los campos: TIPOS DE CAMPOS
Los siguientes tipos de campos comunes:
| NOMBRE DEL CAMPO | DESCRIPCIÓN |
|---|---|
| AutoField | Es un IntegerField que se incrementa automáticamente. |
| BigAutoField | Es un entero de 64 bits, muy parecido a un AutoField, excepto que se garantiza que se ajusta a los números del 1 al 9223372036854775807. |
| BigIntegerField | Es un número entero de 64 bits, muy parecido a un IntegerField, excepto que se garantiza que se ajusta a números de -9223372036854775808 a 9223372036854775807. |
| BinaryField | Un campo para almacenar datos binarios sin procesar. |
| BooleanField | Un campo verdadero / falso. El widget de formulario predeterminado para este campo es CheckboxInput. |
| CharField | Es una fecha, representada en Python por una instancia de datetime.date. |
| DateField | Una fecha, representada en Python por una instancia de datetime.date |
| Se utiliza para la fecha y la hora, representada en Python por una instancia de datetime.datetime. | |
| DecimalField | Es un número decimal de precisión fija, representado en Python por una instancia Decimal. |
| DurationField | Un campo para almacenar períodos de tiempo. |
| EmailField | Es un CharField que verifica que el valor sea una dirección de correo electrónico válida. |
| FileField | Es un campo de carga de archivos. |
| FloatField | Es un número de punto flotante representado en Python por una instancia flotante. |
| ImageField | Hereda todos los atributos y métodos de FileField, pero también valida que el objeto cargado es una imagen válida. |
| IntegerField | Es un campo entero. Los valores de -2147483648 a 2147483647 están seguros en todas las bases de datos compatibles con Django. |
| GenericIPAddressField | Una dirección IPv4 o IPv6, en formato de cadena(por ejemplo, 192.0.2.30 o 2a02: 42fe :: 4). |
| NullBooleanField | Como BooleanField, pero permite NULL como una de las opciones. |
| PositiveIntegerField | Como un IntegerField, pero debe ser positivo o cero(0). |
| PositivoSmallIntegerField | Como PositiveIntegerField, pero solo permite valores bajo un cierto punto(dependiente de la base de datos). |
| SlugField | Slug es un término periodístico. Una slug es una etiqueta corta para algo, que contiene solo letras, números, guiones bajos o guiones. Generalmente se utilizan en URL. |
| SmallIntegerField | Es como un IntegerField, pero solo permite valores bajo un cierto punto(dependiente de la base de datos). |
| TextField | Un campo de texto grande. El widget de formulario predeterminado para este campo es un área de texto. |
| TimeField | Una hora, representada en Python por una instancia de datetime.time. |
| URLField | Un CharField para una URL, validado por URLValidator. |
| UUIDField | Un campo para almacenar identificadores únicos universales. Utiliza la clase UUID de Python. Cuando se usa en PostgreSQL, esto se almacena en un tipo de datos uuid, de lo contrario en un char(32). |
Argumento de los Campos
Los siguientes argumentos son comunes a la mayoría de los tipos de campo y pueden usarse al declararlos:
-
max_length=20--- Establece que la longitud máxima del valor de este campo es 20 caracteres. -
help_text="Enter field documentation"--- proporciona una etiqueta de texto para mostrar que ayuda a los usuarios a saber qué valor proporcionar cuando un usuario ha de introducirlo via un formulario HTML. -
help_text: Proporciona una etiqueta de texto para formularios HTML (ej. en el sitio de Administración), tal como se describe arriba.
-
verbose_name: Nombre de fácil lectura que se usa en etiquetas para el campo. Si no se especifica, Django inferirá el valor por defecto del verbose name a partir del nombre del campo.
-
default: Valor por defecto para el campo. Puede ser un valor o un callable object (objeto que puede ser llamado como una función), en cuyo caso el objeto será llamado cada vez que se cree un nuevo registro.
-
null: Si es
True, Django guardará valores en blanco o vacíos comoNULLen la base de datos para campos donde sea apropiado (unCharFieldguardará una cadena vacía en su lugar). Por defecto esFalse. -
blank: Si es
True, se permite que el campo quede en blanco en tus formularios. El valor por defecto esFalse, lo que significa que la validación de formularios de Django te forzará a introducir un valor. Con frecuencia se usa connull=True, porque si vas a permitir valores en blanco, también querrás que la base de datos sea capaz de representarlos de forma apropiada. -
choices: Un grupo de valores de selección para este campo. Si se proporciona, el widget correspondiente por defecto del formulario será una caja de selección con estos valores de selección en vez del campo de texto estándar.
-
primary_key: Si es
True, establece el campo actual como clave primaria para el modelo (Una clave primaria es una columna especial de la base de datos, diseñada para identificar de forma única todos los diferentes registros de una tabla). Si no se especifica ningún campo como clave primaria, Django añadirá automáticamente un campo para este propósito.
Métodos
Un modelo puede tener también métodos
Minimamente, en cada modelo deberías definir el método estándar de las clases de Python __str__() para devolver una cadena de texto legible por humanos para cada objeto. Esta cadena se usa para representar registros individuales en el sitio de administración (y en cualquier otro lugar donde necesites referirte a una instancia del modelo). Con frecuencia éste devolverá un título o nombre de campo del modelo.
Recuerde que self.name==> self, indica que estamos en una función dentro de una clase, es decir un método y nombre hace referencia a la propiedad o variable de la clase.
Metadatos
Puedes declarar metadatos a nivel de modelo para tu Modelo declarando class Meta, tal como se muestra.
La forma en que aparecen los modelos en el admin que genera Django.
Codigo de los modelos
Aplicacion Client
from django.db import models
# Create your models here.
class Client(models.Model):
STATUS_CHOICES = [
('ACTIVE', 'Active'),
('INACTIVE', 'Inactive'),
]
name = models.CharField(max_length=100, help_text="Ingrese el Nombre del Cliente")
address = models.CharField(max_length=100, help_text="Ingrese la Direccion del Cliente")
phone = models.CharField(max_length=12, help_text="Ingrese el Telefono del Cliente")
email = models.EmailField(max_length=100, help_text="Ingrese el Correo del Cliente", unique=True)
password = models.CharField(max_length=100, help_text="Ingrese el Password del Cliente")
status = models.CharField(
max_length=8,
choices=STATUS_CHOICES,
default='ACTIVE',
help_text="Ingrese el Estado del Cliente"
)
def __str__(self):
return self.name
class Meta:
verbose_name = "cliente"
verbose_name_plural = "clientes"
Aplicacion Product
from django.db import models
# Create your models here.
class ProductType(models.Model):
STATUS_CHOICES = [
('ACTIVE', 'Active'),
('INACTIVE', 'Inactive'),
]
name = models.CharField(max_length=100, help_text="Ingrese el Nombre del Tipo de Producto")
description = models.TextField(help_text="Ingrese la Descripción del Tipo de Producto")
status = models.CharField(
max_length=8,
choices=STATUS_CHOICES,
default='ACTIVE',
help_text="Ingrese el Estado del Tipo de Producto"
)
def __str__(self):
return self.name
class Meta:
verbose_name = "tipo de producto"
verbose_name_plural = "tipos de productos"
class Product(models.Model):
STATUS_CHOICES = [
('ACTIVE', 'Active'),
('INACTIVE', 'Inactive'),
]
name = models.CharField(max_length=100, help_text="Ingrese el Nombre del Producto")
brand = models.CharField(max_length=100, help_text="Ingrese la Marca del Producto")
price = models.DecimalField(max_digits=10, decimal_places=2, help_text="Ingrese el Precio del Producto")
min_stock = models.PositiveIntegerField(help_text="Ingrese el Stock Mínimo del Producto")
quantity = models.PositiveIntegerField(help_text="Ingrese la Cantidad del Producto")
product_type = models.ForeignKey(
ProductType,
on_delete=models.CASCADE,
help_text="Seleccione el Tipo de Producto"
)
status = models.CharField(
max_length=8,
choices=STATUS_CHOICES,
default='ACTIVE',
help_text="Ingrese el Estado del Producto"
)
def __str__(self):
return f"{self.name} - {self.brand}"
class Meta:
verbose_name = "producto"
verbose_name_plural = "productos"
Aplicacion Sale
from django.db import models
from myapps.client.models import Client
from myapps.product.models import Product
# Create your models here.
class Sale(models.Model):
STATUS_CHOICES = [
('ACTIVE', 'Active'),
('INACTIVE', 'Inactive'),
]
sale_date = models.DateTimeField(auto_now_add=True, help_text="Fecha de la Venta")
subtotal = models.DecimalField(max_digits=10, decimal_places=2, help_text="Ingrese el Subtotal de la Venta")
tax = models.DecimalField(max_digits=10, decimal_places=2, help_text="Ingrese el Impuesto de la Venta")
discounts = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, help_text="Ingrese los Descuentos de la Venta")
total = models.DecimalField(max_digits=10, decimal_places=2, help_text="Ingrese el Total de la Venta")
status = models.CharField(
max_length=8,
choices=STATUS_CHOICES,
default='ACTIVE',
help_text="Ingrese el Estado de la Venta"
)
client = models.ForeignKey(
Client,
on_delete=models.CASCADE,
help_text="Seleccione el Cliente"
)
products = models.ManyToManyField(
Product,
through='ProductSale',
help_text="Productos de la Venta"
)
def __str__(self):
return f"Venta #{self.id} - {self.client.name} - {self.sale_date.strftime('%Y-%m-%d')}"
class Meta:
verbose_name = "venta"
verbose_name_plural = "ventas"
class ProductSale(models.Model):
total = models.DecimalField(max_digits=10, decimal_places=2, help_text="Ingrese el Total del Producto en la Venta")
product = models.ForeignKey(
Product,
on_delete=models.CASCADE,
help_text="Seleccione el Producto"
)
sale = models.ForeignKey(
Sale,
on_delete=models.CASCADE,
help_text="Seleccione la Venta"
)
def __str__(self):
return f"{self.product.name} - Venta #{self.sale.id}"
class Meta:
verbose_name = "producto venta"
verbose_name_plural = "productos ventas"
unique_together = ('product', 'sale')
Una vez definido losl modelos, procedemos a crear las migraciones y la generación física de la base de datos, ingresamos en la terminal de visual studio code. (Con el ambiente virtual activado)
Puede revisar la generacion de las tablas en Dbeaver
