Está en la página 1de 222

1.

PYTHON

Python es un lenguaje de programación interpretado, el código fuente se interpreta línea por


línea en tiempo de ejecución, de alto nivel y de propósito general. Fue creado a finales de la
década de 1980 por Guido van Rossum y se ha vuelto muy popular debido a su diseño elegante,
su sintaxis intuitiva y su enfoque en la legibilidad del código.

Python se destaca por su facilidad de uso y su capacidad de ser utilizado en una amplia gama de
aplicaciones. Es utilizado en el desarrollo de software, el análisis de datos, la inteligencia artificial,
la creación de sitios web y muchas otras áreas.

Una de las características distintivas de Python es su filosofía de bibliotecas, lo que significa que
la biblioteca estándar de Python proporciona una amplia gama de módulos y funciones que
cubren muchas necesidades comunes. Además, hay una gran cantidad de bibliotecas y marcos
de terceros disponibles que amplían aún más la funcionalidad de Python.

La sintaxis de Python se caracteriza por ser fácil de leer y entender.

Python es compatible con múltiples sistemas operativos, como Windows, macOS y Linux, lo que
lo convierte en una opción versátil para el desarrollo de software.

Ventajas de Python

• Sintaxis clara y legible: Python se caracteriza por una sintaxis limpia y fácil de leer. Utiliza
la indentación en lugar de llaves o palabras clave para delimitar bloques de código, lo
que fomenta la escritura de código limpio y estructurado.
• Facilidad de aprendizaje: Python es considerado uno de los lenguajes de programación
más accesibles para principiantes. Su sintaxis simple y su enfoque en la legibilidad hacen
que sea más fácil de entender y aprender en comparación con otros lenguajes.
• Amplia comunidad y recursos: Python cuenta con una comunidad de desarrolladores
activa y comprometida. Esto significa que hay una gran cantidad de recursos disponibles,
como bibliotecas, módulos y marcos de trabajo, que facilitan el desarrollo de una amplia
gama de aplicaciones.
• Versatilidad y portabilidad: Python es un lenguaje multipropósito que se puede utilizar
en una amplia variedad de aplicaciones y dominios. Puedes utilizar Python para
desarrollar software, crear aplicaciones web, realizar análisis de datos, implementar
inteligencia artificial, automatizar tareas, entre muchas otras cosas. Además, Python es
compatible con diferentes sistemas operativos, lo que lo hace altamente portable.
• "Baterías incluidas": La biblioteca estándar de Python ofrece una amplia gama de
módulos y funciones que cubren muchas necesidades comunes, como manipulación de
cadenas, acceso a bases de datos, procesamiento de archivos, entre otros. Esto evita
tener que buscar y descargar módulos externos para muchas tareas básicas.
• Integración con otros lenguajes: Python se puede integrar fácilmente con otros
lenguajes de programación, lo que permite utilizar bibliotecas y componentes existentes
en diferentes tecnologías. Por ejemplo, se puede utilizar Python como una interfaz de
scripting para aplicaciones escritas en C++.
• Enfoque en la legibilidad y productividad: Python se centra en la escritura de código claro
y conciso. Esto no solo hace que el código sea más fácil de leer, sino que también mejora
la productividad, ya que los programadores pueden desarrollar aplicaciones más
rápidamente y con menos líneas de código en comparación con otros lenguajes.

1
2. Donde se usa Python?

• Desarrollo de software: Python se utiliza para desarrollar una amplia variedad de


aplicaciones de software, desde aplicaciones de escritorio hasta aplicaciones web y
móviles. Su legibilidad y productividad lo convierten en una elección popular para
proyectos de desarrollo.
• Análisis de datos y ciencia de datos: Python es ampliamente utilizado en el análisis y
procesamiento de datos. Bibliotecas populares como NumPy, Pandas y Matplotlib
brindan poderosas herramientas para la manipulación y visualización de datos, y se ha
convertido en una opción preferida para científicos de datos y analistas.
• Inteligencia artificial y aprendizaje automático: Python es un lenguaje muy utilizado en
el campo de la inteligencia artificial y el aprendizaje automático. Bibliotecas como
TensorFlow, Keras y PyTorch permiten desarrollar y entrenar modelos de aprendizaje
automático de manera eficiente.
• Automatización y scripting: Python es una opción popular para la automatización de
tareas y scripting. Su sintaxis legible y su amplia biblioteca estándar lo hacen ideal para
escribir scripts que automatizan tareas repetitivas, procesamiento de archivos,
extracción de datos, entre otros.
• Desarrollo web: Python es ampliamente utilizado en el desarrollo web. Frameworks
como Django y Flask permiten crear aplicaciones web de manera rápida y eficiente.
Además, Python es utilizado en la creación de servidores web, APIs y scraping web.
• Internet de las cosas (IoT): Python es utilizado en el desarrollo de aplicaciones y
dispositivos de Internet de las cosas. Su facilidad de uso y amplio soporte de hardware
lo convierten en una opción adecuada para el desarrollo de proyectos IoT.
• Automatización de pruebas: Python se utiliza en la automatización de pruebas de
software. Frameworks como Selenium y Pytest permiten escribir y ejecutar pruebas
automatizadas, lo que ayuda a mejorar la calidad del software y acelerar el proceso de
desarrollo.

3. TIPOS DE DATOS BASICOS


3.1. Enteros (int):

Representan números enteros sin parte decimal. Por ejemplo:


edad = 25
cantidad_productos = 100

Los enteros se utilizan para contar, realizar cálculos matemáticos y representar índices de listas
o arreglos.
# Operaciones matemáticas con enteros
x = 5
y = 3

2
# Suma
suma = x + y
print("La suma de", x, "y", y, "es:", suma)

# Resta
resta = x - y
print("La resta de", x, "y", y, "es:", resta)

# Multiplicación
multiplicacion = x * y
print("La multiplicación de", x, "y", y, "es:", multiplicacion)

# División (con resultado de punto flotante)


division = x / y
print("La división de", x, "y", y, "es:", division)

# División entera (descartando el residuo)


division_entera = x // y
print("La división entera de", x, "y", y, "es:", division_entera)

# Módulo (residuo de la división)


modulo = x % y
print("El módulo de", x, "y", y, "es:", modulo)

# Potencia
potencia = x ** y
print(x, "elevado a la", y, "es:", potencia)

3.2. Números de punto flotante (float):

Representan números con parte decimal. Por ejemplo:


precio = 19.99
pi = 3.14159

3
Los números de punto flotante se utilizan en cálculos científicos, operaciones matemáticas más
precisas y en situaciones que requieren representar valores con decimales.
# Operaciones con números de punto flotante
precio_producto = 9.99
descuento = 0.20

# Calcular precio con descuento


precio_con_descuento = precio_producto - (precio_producto *
descuento)
print("El precio con descuento es:", precio_con_descuento)

# Realizar cálculos matemáticos con números de punto flotante


radio = 2.5
area_circulo = 3.14159 * radio**2
print("El área del círculo es:", area_circulo)

# División con punto flotante


resultado = 10 / 3
print("El resultado de la división es:", resultado)

# Redondear números de punto flotante


numero = 3.789
numero_redondeado = round(numero, 2)
print("El número redondeado a 2 decimales es:", numero_redondeado)

3.3. Cadenas de texto (str):

Representan secuencias de caracteres. Por ejemplo:


nombre = "Juan"
mensaje = "¡Hola, bienvenido!"

Las cadenas de texto se utilizan para almacenar y manipular texto, como nombres, mensajes,
direcciones, entre otros.
# Crear variables de tipo str
nombre = "María"

4
mensaje = "¡Hola, bienvenido!"

# Concatenación de cadenas
saludo = "Hola, " + nombre + ". " + mensaje
print(saludo)

# Acceso a caracteres individuales


primer_caracter = nombre[0]
ultimo_caracter = nombre[-1]
print("Primer carácter:", primer_caracter)
print("Último carácter:", ultimo_caracter)

# Obtener longitud de una cadena


longitud = len(nombre)
print("Longitud de la cadena:", longitud)

# Método upper() y lower()


mayusculas = nombre.upper()
minusculas = nombre.lower()
print("En mayúsculas:", mayusculas)
print("En minúsculas:", minusculas)

# Buscar una subcadena


frase = "Python es divertido"
posicion = frase.index("divertido")
print("Posición de 'divertido':", posicion)

# Reemplazar parte de una cadena


frase_reemplazada = frase.replace("divertido", "genial")
print("Frase reemplazada:", frase_reemplazada)

3.4. Booleanos (bool):

Representan valores de verdad, verdadero (True) o falso (False). Por ejemplo:

5
activo = True
mayor_edad = False

Los booleanos se utilizan en expresiones lógicas, condiciones y control de flujo para tomar
decisiones basadas en condiciones.
# Variables booleanas
verdadero = True
falso = False
# Operaciones lógicas
a = 10
b = 5
resultado_and = (a > 5) and (b < 10)
print("Resultado de la operación AND:", resultado_and)
resultado_or = (a > 5) or (b > 10)
print("Resultado de la operación OR:", resultado_or)
resultado_not = not (a > b)
print("Resultado de la operación NOT:", resultado_not)

4. FUNCION TYPE

La función type() en Python se utiliza para obtener el tipo de dato de un objeto o variable.

Su sintaxis es la siguiente: type(objeto). Donde objeto puede ser cualquier variable, valor o
expresión en Python.

uso la función type():

En el primer ejemplo, se declara una variable x y se utiliza la función type() para obtener su tipo
de dato, que en este caso es int (entero).
# Ejemplo 1: Obtener el tipo de dato de una variable
x = 5
tipo_x = type(x)
print(tipo_x) # Imprime <class 'int'>

En el segundo ejemplo, se realiza una operación de división y se utiliza la función type() para
obtener el tipo de dato del resultado, que en este caso es float (número de punto flotante).
# Ejemplo 2: Obtener el tipo de dato de una expresión
resultado = 10 / 3
tipo_resultado = type(resultado)
print(tipo_resultado) # Imprime <class 'float'>

6
En el tercer ejemplo, se declara una variable cadena y se utiliza la función type() para obtener el
tipo de dato de la cadena, que en este caso es str (cadena de texto).
# Ejemplo 3: Obtener el tipo de dato de un objeto
cadena = "Hola"
tipo_cadena = type(cadena)
print(tipo_cadena) # Imprime <class 'str'>

La función type() es útil cuando necesitas saber el tipo de dato de una variable u objeto en
Python. Puedes utilizar esta información para realizar comprobaciones o tomar decisiones
basadas en el tipo de dato.

5. OPERADORES
5.1. Matemáticos

Suma (+): Se utiliza para sumar dos valores.


x = 5
y = 3
suma = x + y
print(suma) # Imprime 8

Resta (-): Se utiliza para restar un valor de otro.


x = 5
y = 3
resta = x - y
print(resta) # Imprime 2

Multiplicación (*): Se utiliza para multiplicar dos valores.


x = 5
y = 3
multiplicacion = x * y
print(multiplicacion) # Imprime 15

División (/): Se utiliza para dividir un valor por otro. El resultado siempre es de tipo float.
x = 10
y = 3
division = x / y
print(division) # Imprime 3.3333333333333335

División entera (//): Se utiliza para dividir un valor por otro y obtener la parte entera del
resultado, descartando cualquier residuo decimal.
x = 10

7
y = 3
division_entera = x // y
print(division_entera) # Imprime 3

Módulo (%): Se utiliza para obtener el residuo de la división entera entre dos valores.
x = 10
y = 3
modulo = x % y
print(modulo) # Imprime 1

Potencia (**): Se utiliza para elevar un valor a una potencia.


x = 2
y = 3
potencia = x ** y
print(potencia) # Imprime 8

5.2. Comparación

Igualdad (==): Comprueba si dos valores son iguales.


x = 5
y = 3
igual = x == y
print(igual) # Imprime False

Desigualdad (!=): Comprueba si dos valores no son iguales.


x = 5
y = 3
desigual = x != y
print(desigual) # Imprime True

Mayor que (>): Comprueba si un valor es mayor que otro.


x = 5
y = 3
mayor = x > y
print(mayor) # Imprime True

Menor que (<): Comprueba si un valor es menor que otro.

8
x = 5
y = 3
menor = x < y
print(menor) # Imprime False

Mayor o igual que (>=): Comprueba si un valor es mayor o igual que otro.
x = 5
y = 3
mayor_igual = x >= y
print(mayor_igual) # Imprime True

Menor o igual que (<=): Comprueba si un valor es menor o igual que otro.
x = 5
y = 3
menor_igual = x <= y
print(menor_igual) # Imprime False

5.3. Operadores logicos

AND lógico (and): Retorna True si ambas expresiones son verdaderas.


x = 5
y = 3
z = 7
resultado = (x > y) and (y < z)
print(resultado) # Imprime True

OR lógico (or): Retorna True si al menos una de las expresiones es verdadera.


x = 5
y = 3
z = 7
resultado = (x > y) or (y > z)
print(resultado) # Imprime True

NOT lógico (not): Retorna la negación de una expresión, invirtiendo su valor booleano.
x = 5
y = 3

9
resultado = not (x > y)
print(resultado) # Imprime False

6. Palabras reservadas

En Python, una palabra reservada (también conocida como palabra clave) es un término que
tiene un significado especial y está reservado para su uso específico dentro del lenguaje. Estas
palabras reservadas no pueden ser utilizadas como nombres de variables, funciones o cualquier
otro identificador en tu código, ya que tienen un propósito definido en el lenguaje.

Aquí tienes una lista de las palabras reservadas en Python:

• False: Representa el valor booleano falso.


• None: Representa la ausencia de un valor o la falta de definición.
• True: Representa el valor booleano verdadero.
• and: Operador lógico AND.
• as: Se utiliza en la declaración import para renombrar un módulo.
• assert: Se utiliza para verificar que una condición sea verdadera.
• break: Se utiliza para salir de un bucle (for o while).
• class: Se utiliza para definir una clase.
• continue: Se utiliza para pasar a la siguiente iteración de un bucle sin ejecutar el código
restante en esa iteración.
• def: Se utiliza para definir una función.
• del: Se utiliza para eliminar una variable o un elemento de una lista.
• elif: Abreviatura de "else if", se utiliza en estructuras de control condicionales.
• else: Se utiliza en estructuras de control condicionales para definir un bloque de código
que se ejecuta cuando ninguna de las condiciones anteriores es verdadera.
• except: Se utiliza en bloques try-except para manejar excepciones.
• finally: Se utiliza en bloques try-except para definir un bloque de código que siempre se
ejecuta, independientemente de si se produjo una excepción o no.
• for: Se utiliza para iterar sobre elementos en una secuencia.
• from: Se utiliza en la declaración import para importar un módulo o elementos
específicos de un módulo.
• global: Se utiliza para indicar que una variable se debe tratar como global dentro de una
función.
• if: Se utiliza para definir una estructura de control condicional.
• import: Se utiliza para importar un módulo.
• in: Se utiliza para verificar si un valor está presente en una secuencia.
• is: Se utiliza para verificar si dos objetos son el mismo objeto.
• lambda: Se utiliza para definir funciones lambda (funciones anónimas).
• nonlocal: Se utiliza para indicar que una variable no es local, sino que se encuentra en
un alcance superior dentro de funciones anidadas.
• not: Operador lógico NOT.
• or: Operador lógico OR.
• pass: Se utiliza como un marcador de posición para un bloque de código vacío.
• raise: Se utiliza para generar una excepción manualmente.
• return: Se utiliza para devolver un valor desde una función.
• try: Se utiliza para definir un bloque de código que puede generar una excepción.

10
• while: Se utiliza para crear un bucle que se repite mientras una condición sea verdadera.
• with: Se utiliza para trabajar con un contexto de manejo de recursos.
• yield: Se utiliza en generadores para producir un valor en cada iteración.

Estas son las palabras reservadas en Python a partir de la versión 3.9.

7. Entrada por teclado

La entrada por teclado, también conocida como entrada estándar, es una forma de interactuar
con un programa ingresando datos desde el teclado. En Python, puedes utilizar la función input()
para solicitar la entrada del usuario y almacenarla en una variable.

La función input() muestra un mensaje opcional en la consola y espera a que el usuario ingrese
una línea de texto. Luego, devuelve esa línea de texto como una cadena (str) que puedes asignar
a una variable para su posterior procesamiento.

Ejemplo de cómo usar input() para obtener entrada por teclado:


nombre = input("Ingresa tu nombre: ")
print("¡Hola,", nombre, "!")
edad = input("Ingresa tu edad: ")
print("Tu edad es:", edad)

En este ejemplo, se utilizan dos llamadas a input(). La primera línea solicita al usuario que ingrese
su nombre y lo asigna a la variable nombre. Luego, se imprime un saludo personalizado con el
nombre ingresado.

La segunda línea solicita al usuario que ingrese su edad y la asigna a la variable edad. Luego, se
imprime la edad ingresada.

Es importante tener en cuenta que input() siempre devuelve una cadena (str), incluso si el
usuario ingresa un número. Si necesitas trabajar con datos numéricos, es posible que debas
convertir la entrada a un tipo de dato numérico apropiado utilizando funciones como int() o
float().

Solicitar múltiples valores de entrada y realizar cálculos:


num1 = float(input("Ingresa el primer número: "))
num2 = float(input("Ingresa el segundo número: "))

suma = num1 + num2


resta = num1 - num2
producto = num1 * num2

print("La suma es:", suma)


print("La resta es:", resta)
print("El producto es:", producto)

11
En este ejemplo, se solicitan dos números al usuario utilizando input(). Los números se
convierten a tipo float utilizando float() para permitir cálculos decimales. Luego, se realizan
cálculos de suma, resta y producto de los dos números ingresados y se imprimen los resultados.

Recuerda que al utilizar input(), el programa esperará hasta que el usuario ingrese la información
y presione la tecla "Enter" antes de continuar con la ejecución.

12
1. FUNCIONES

En Python, una función es un bloque de código reutilizable que realiza una tarea específica. Las
funciones se utilizan para dividir un programa en fragmentos más pequeños y manejables, lo
que facilita el desarrollo, la organización y la reutilización del código. Para usar una función,
primero debes definirla y luego puedes llamarla desde otras partes del programa.

Definición básica de una función:


def nombre_de_funcion():
# Código de la función
# ...

def es la palabra clave utilizada para definir una función.

nombre_de_funcion es el nombre que le das a tu función. Puedes elegir cualquier nombre válido
de acuerdo con las convenciones de nomenclatura de Python.

Los paréntesis vacíos () se utilizan para indicar que la función no requiere ningún argumento.

El bloque de código de la función se indentará y contendrá las instrucciones que se ejecutarán


cuando se llame a la función.

Llamada básica a una función:


nombre_de_funcion() # Llamada a la función

Para llamar a una función, simplemente escribe su nombre seguido de paréntesis ().

Ejemplo básico:
def saludar():
print("Hola, ¡bienvenido!")
saludar() # Imprime "Hola, ¡bienvenido!"

En este ejemplo, se define una función llamada saludar() que imprime un mensaje de
bienvenida. Luego, se llama a la función utilizando saludar() y se imprime el mensaje.

Ejemplo:

En este ejemplo, se define una función llamada suma() que toma dos argumentos a y b, y
devuelve la suma de los dos valores. Luego, se llama a la función con los argumentos 5 y 3, y se
asigna el resultado a la variable resultado. Finalmente, se imprime el valor de resultado, que es
8.
def suma(a, b):
return a + b
resultado = suma(5, 3)
print(resultado) # Imprime 8

1
El uso más común de las funciones en Python es la modularización y reutilización del código.
Aquí tienes algunas de las aplicaciones más comunes de las funciones en Python:

• Abstracción y organización del código: Las funciones permiten dividir un programa en


bloques más pequeños y manejables, lo que facilita la comprensión y el mantenimiento
del código. Puedes definir funciones para realizar tareas específicas y luego llamarlas
según sea necesario.
• Reutilización del código: Al definir una función, puedes usarla en múltiples lugares de tu
programa sin tener que repetir el mismo código una y otra vez. Esto mejora la legibilidad,
reduce la duplicación y facilita los cambios y actualizaciones futuras.
• Encapsulamiento de la lógica: Las funciones permiten encapsular la lógica y la
funcionalidad en un bloque separado, lo que hace que el código sea más modular y fácil
de entender. Esto promueve la separación de preocupaciones y ayuda a crear programas
más estructurados y mantenibles.
• Abstracción de tareas repetitivas: Si tienes un conjunto de instrucciones que se repiten
en varios lugares de tu programa, puedes encapsular esas instrucciones en una función
y llamarla cada vez que necesites ejecutar esa tarea. Esto simplifica el código y evita
errores causados por la repetición manual de código.
• Manejo de argumentos y valores de retorno: Las funciones te permiten definir
parámetros (argumentos) que pueden ser pasados a la función al llamarla. Además,
puedes utilizar la declaración return para devolver valores desde la función. Esto facilita
la personalización y la flexibilidad de las funciones.

2. FUNCIONES INCORPORADAS A PYTHON MAS UTILIZADAS

Python ofrece una amplia variedad de funciones incorporadas (built-in functions) que son
ampliamente utilizadas en el desarrollo de programas. Algunas de las funciones más comunes y
útiles en Python incluyen:

print(): Imprime mensajes en la consola o en la salida estándar.


print("Hola, mundo!")

input(): Lee una línea de texto ingresada por el usuario desde la entrada estándar.
nombre = input("Ingresa tu nombre: ")

len(): Devuelve la longitud (cantidad de elementos) de un objeto, como una cadena, lista, tupla
o diccionario.
texto = "Hola"
longitud = len(texto)

range(): Genera una secuencia de números dentro de un rango especificado.


for i in range(1, 5):
print(i)

type(): Devuelve el tipo de datos de un objeto.


numero = 10

2
tipo = type(numero)

str(), int(), float(): Convierten un objeto a una cadena, entero o flotante, respectivamente.
numero_str = str(10)
numero_int = int("15")
numero_float = float("3.14")

list(), tuple(), set(), dict(): Crea un objeto de tipo lista, tupla, conjunto o diccionario,
respectivamente.
mi_lista = list([1, 2, 3])
mi_tupla = tuple((4, 5, 6))
mi_conjunto = set([7, 8, 9])
mi_diccionario = dict(nombre="Juan", edad=25)

max(), min(), sum(): Calculan el valor máximo, mínimo y la suma de una secuencia de números,
respectivamente.
numeros = [10, 5, 8, 3]
maximo = max(numeros)
minimo = min(numeros)
suma = sum(numeros)

upper(), lower(): Convierte una cadena a mayúsculas o minúsculas, respectivamente.


texto = "Hola"
mayusculas = texto.upper()
minusculas = texto.lower()

capitalize(): Convierte el primer carácter de una cadena en mayúscula y el resto en minúsculas.


texto = "hola mundo"
capitalizado = texto.capitalize()

strip(), lstrip(), rstrip(): Elimina los espacios en blanco al principio y/o al final de una cadena.
texto = " Hola "
sin_espacios = texto.strip()
sin_espacios_izquierda = texto.lstrip()
sin_espacios_derecha = texto.rstrip()

split(): Divide una cadena en una lista de subcadenas utilizando un separador especificado.
texto = "Hola,como,estas"
subcadenas = texto.split(",")

join(): Concatena una lista de cadenas utilizando un separador especificado.

3
subcadenas = ["Hola", "como", "estas"]
texto = "-".join(subcadenas)

replace(): Reemplaza todas las apariciones de una subcadena por otra en una cadena.
texto = "Hola mundo"
nuevo_texto = texto.replace("mundo", "amigo")

3. ESTRUCTURAS DE CONTROL

Una estructura de control en programación se utiliza para alterar el flujo de ejecución de un


programa, permitiendo la toma de decisiones y la repetición de bloques de código según ciertas
condiciones. En Python, existen varias estructuras de control que te permiten controlar el flujo
de ejecución de tu programa.

Las principales estructuras de control en Python son las siguientes:

Estructura if-else: Permite ejecutar un bloque de código si se cumple una condición, y otro
bloque de código si no se cumple la condición.
if condicion:
# Bloque de código si se cumple la condición
else:
# Bloque de código si no se cumple la condición

Estructura elif (else if): Se utiliza para evaluar múltiples condiciones secuenciales.
if condicion1:
# Bloque de código si se cumple la primera condición
elif condicion2:
# Bloque de código si se cumple la segunda condición
else:
# Bloque de código si no se cumple ninguna de las condiciones
anteriores

Ejemplo:

En este ejemplo, se define una función llamada calcular_precio_descuento que toma dos
parámetros: precio y descuento. La función verifica diferentes condiciones utilizando la
estructura if para calcular y mostrar el precio con descuento.

• La primera condición verifica que el precio sea mayor que cero. Si es así, continúa
evaluando las siguientes condiciones.
• La segunda condición verifica si el descuento está en el rango de 0 a 100. Si se cumple,
se calcula el precio_final aplicando el descuento proporcionado.
• Si el descuento es igual a cero, se imprime un mensaje indicando que no hay descuento
aplicado.

4
• Si el descuento no está en el rango válido, se imprime un mensaje de error.
• Si el precio no es mayor que cero, se imprime un mensaje indicando que el precio debe
ser mayor que cero.
• Luego, se llaman a la función calcular_precio_descuento con diferentes valores de precio
y descuento para probar las diferentes condiciones y ver los resultados en función de los
valores ingresados.
def calcular_precio_descuento(precio, descuento):
if precio > 0:
if descuento > 0 and descuento <= 100:
precio_final = precio - (precio * descuento / 100)
print(f"El precio con descuento es: {precio_final}")
elif descuento == 0:
print("No hay descuento aplicado.")
else:
print("El descuento debe ser un valor entre 0 y 100.")
else:
print("El precio debe ser mayor que cero.")

calcular_precio_descuento(100, 20) # Precio con descuento: 80.0


calcular_precio_descuento(200, 0) # No hay descuento aplicado.
calcular_precio_descuento(150, 150) # El descuento debe ser un
valor entre 0 y 100.
calcular_precio_descuento(0, 10) # El precio debe ser mayor
que cero.

Estructura de bucle for: Permite iterar sobre una secuencia (como una lista, una tupla o una
cadena) o sobre un rango de números.
for elemento in secuencia:
# Bloque de código a ejecutar en cada iteración

Ejemplo:

Se utiliza un bucle for para iterar sobre una lista de números. Se verifica si cada número es par
utilizando la condición numero % 2 == 0. Si el número es par, se agrega a la variable suma.

Después de que el bucle for ha terminado de iterar sobre todos los números de la lista, se
imprime el resultado de la suma de los números pares.
numeros = [2, 4, 6, 8, 10]
suma = 0

5
for numero in numeros:
if numero % 2 == 0:
suma += numero

print(f"La suma de los números pares es: {suma}")

Estructura de bucle while: Se utiliza para repetir un bloque de código mientras se cumpla una
condición.
while condicion:
# Bloque de código a ejecutar mientras se cumple la condición

Ejemplo:

En este ejemplo, se genera un número secreto aleatorio entre 1 y 100 utilizando el módulo
random. Luego, se inicia un bucle while que se ejecuta infinitamente hasta que el usuario adivine
el número secreto.

En cada iteración del bucle while, se le pide al usuario que ingrese un número y se compara con
el número secreto. Dependiendo de la comparación, se imprime un mensaje indicando si el
número ingresado es mayor o menor que el número secreto.

Si el usuario adivina el número, se imprime un mensaje de felicitaciones junto con la cantidad de


intentos realizados, y se utiliza la instrucción break para salir del bucle while.
import random
intentos = 0
numero_secreto = random.randint(1, 100)
print("¡Adivina el número secreto!")
while True:
intentos += 1
numero_adivinar = int(input("Ingresa un número: "))
if numero_adivinar == numero_secreto:
print(f"¡Felicidades! Adivinaste el número en {intentos}
intentos.")
break
elif numero_adivinar < numero_secreto:
print("El número ingresado es menor al número secreto.")
else:
print("El número ingresado es mayor al número secreto.")

6
Estructura de bucle do-while (no está disponible de forma directa en Python): Aunque Python
no tiene una estructura de bucle do-while incorporada, se puede simular utilizando un bucle
while con una condición de salida al final.
while True:
# Bloque de código a ejecutar al menos una vez
if not condicion:
break # Condición de salida del bucle

4. USO DE IF – ElIf

La elección entre usar if-else o elif depende de la lógica que deseas implementar en tu programa.
Aquí tienes algunas consideraciones para ayudarte a decidir cuál usar en diferentes situaciones:

if-else:

• Se utiliza cuando solo tienes dos posibles caminos o resultados en función de una
condición.
• El bloque de código dentro del if se ejecuta si la condición es verdadera, mientras que el
bloque de código dentro del else se ejecuta si la condición es falsa.
• Si tienes más de dos posibilidades y solo necesitas evaluar una vez, puedes utilizar varios
if-else encadenados.

Ejemplo de uso de if-else:


edad = 18
if edad >= 18:
print("Eres mayor de edad")
else:
print("Eres menor de edad")

elif:

• Se utiliza cuando tienes múltiples condiciones y deseas evaluarlas secuencialmente.


• Evita evaluar todas las condiciones una vez que se encuentra una que sea verdadera.
• Se ejecuta el bloque de código correspondiente a la primera condición verdadera y luego
se sale del conjunto de condiciones.
• Ejemplo de uso de elif:
puntaje = 85
if puntaje >= 90:
print("Obtuviste una A")
elif puntaje >= 80:
print("Obtuviste una B")
elif puntaje >= 70:
print("Obtuviste una C")

7
else:
print("Obtuviste una D")

En general, si solo necesitas evaluar una condición simple y tienes dos resultados posibles, utiliza
if-else. Por otro lado, si tienes múltiples condiciones y quieres evaluarlas secuencialmente, utiliza
elif.

Recuerda que puedes combinar if-else y elif según tus necesidades para implementar lógica más
compleja y realizar diferentes acciones en función de múltiples condiciones.

5. USO DE FOR O WHILE

En Python, tanto el bucle for como el bucle while son útiles para diferentes situaciones. La
elección entre utilizar uno u otro depende de la tarea específica que deseas realizar. Aquí hay
algunas consideraciones para ayudarte a decidir cuándo usar cada uno:

Bucle for:

• Se utiliza cuando se conoce la cantidad de elementos a iterar, como recorrer una lista,
tupla, cadena o rango de números.
• Es especialmente útil cuando deseas realizar una tarea para cada elemento de una
secuencia.
• La sintaxis es más concisa y legible.
• No necesitas controlar manualmente el contador o la condición de finalización del bucle.

Ejemplo de uso de bucle for:


numeros = [1, 2, 3, 4, 5]
for numero in numeros:
print(numero)

Bucle while:

• Se utiliza cuando no se conoce la cantidad exacta de iteraciones necesarias y se basa en


una condición para continuar o salir del bucle.
• Es útil cuando deseas repetir un bloque de código hasta que se cumpla una determinada
condición.
• Se puede utilizar para implementar lógica más compleja que requiere un mayor control
sobre el flujo de ejecución.

Ejemplo de uso de bucle while:


contador = 0
while contador < 5:
print(contador)
contador += 1

En resumen, si sabes cuántas veces necesitas iterar o quieres realizar una tarea para cada
elemento de una secuencia conocida, el bucle for es la elección adecuada. Por otro lado, si no
sabes cuántas veces necesitas repetir un bloque de código y deseas controlar manualmente la
condición de finalización, el bucle while es más apropiado.

8
En algunos casos, también puedes combinar ambos bucles para lograr el resultado deseado,
utilizando el bucle for para iterar sobre una secuencia conocida y el bucle while para realizar
tareas adicionales o realizar una repetición basada en una condición específica dentro de cada
iteración del bucle for.

9
1. TIPOS DE DATOS COMPLEJOS
Un tipo de dato complejo es un tipo de dato que se utiliza para representar
estructuras de datos más complejas que los tipos de datos básicos como
enteros, flotantes, cadenas de texto, etc.
1.1. LISTAS
En Python, una lista es un tipo de dato que se utiliza para almacenar una
colección ordenada y mutable de elementos (se refiere a la capacidad de un
objeto de ser modificado después de haber sido creado). Puedes pensar en una
lista como una secuencia de elementos que se pueden acceder, modificar y
recorrer.
Para crear una lista en Python, se utilizan corchetes [] y los elementos se separan
por comas. Ejemplo de cómo crear una lista con algunos elementos:
frutas = ["manzana", "banana", "naranja", "pera"]

Puedes acceder a los elementos de una lista utilizando su índice. Los índices
comienzan desde cero para el primer elemento y van aumentando en uno para
cada elemento subsiguiente. Por ejemplo, para acceder al segundo elemento de
la lista frutas, se utiliza frutas[1]:
print(frutas[1]) # Imprime "banana"

También puedes modificar los elementos de una lista asignando un nuevo valor
a un índice específico:
frutas[2] = "mandarina"
print(frutas) # Imprime ["manzana", "banana", "mandarina",
"pera"]
Además, las listas en Python tienen varios métodos incorporados que se pueden
utilizar para realizar operaciones comunes, como agregar elementos, eliminar
elementos, ordenar la lista, etc. Aquí tienes algunos ejemplos de uso de estos
métodos:
# Agregar elementos a una lista
frutas.append("uva") # Agrega "uva" al final de la lista
print(frutas) # Imprime ["manzana", "banana", "mandarina",
"pera", "uva"]

# Eliminar elementos de una lista


frutas.remove("banana") # Elimina el elemento "banana"
print(frutas) # Imprime ["manzana", "mandarina", "pera",
"uva"]

1
# Ordenar una lista
frutas.sort() # Ordena la lista alfabéticamente
print(frutas) # Imprime ["manzana", "mandarina", "pera",
"uva"]

Con las listas usamos estas funciones:


• len(): Retorna la longitud de una lista, es decir, la cantidad de elementos
que contiene.
• append(): Agrega un elemento al final de la lista.
• insert(): Inserta un elemento en una posición específica de la lista.
• remove(): Elimina la primera aparición de un elemento específico de la
lista.
• pop(): Elimina y retorna el último elemento de la lista, o un elemento en
una posición específica si se proporciona un índice.
• index(): Retorna el índice de la primera aparición de un elemento
específico en la lista.
• count(): Retorna la cantidad de veces que un elemento específico aparece
en la lista.
• sort(): Ordena los elementos de la lista en orden ascendente.
• reverse(): Invierte el orden de los elementos en la lista.
• extend(): Combina una lista existente con otra lista o cualquier otro
iterable, agregando sus elementos al final de la lista original.

1.2. TUPLAS
En Python, una tupla es un tipo de dato que se utiliza para almacenar una
colección ordenada e inmutable de elementos. A diferencia de las listas, las
tuplas no pueden modificarse después de su creación. Son objetos estáticos
cuyos elementos no pueden agregarse, eliminarse ni modificarse una vez que
se han definido.
Para crear una tupla en Python, se utilizan paréntesis () y los elementos se
separan por comas. Aquí tienes un ejemplo de cómo crear una tupla:
frutas = ("manzana", "banana", "naranja")
Las tuplas se utilizan principalmente en situaciones en las que se desea asegurar
que los elementos no sean modificados después de su creación. Algunas
razones comunes para utilizar tuplas son:
Asignación múltiple: Las tuplas se pueden utilizar para asignar múltiples
valores a múltiples variables en una sola instrucción.
x, y, z = (10, 20, 30)
Intercambio de valores: Las tuplas se pueden utilizar para intercambiar los
valores de dos variables sin necesidad de una variable temporal adicional.

2
a = 5
b = 10
a, b = b, a # Intercambia los valores de a y b

Retorno de múltiples valores en una función: Una función puede devolver una
tupla que contiene varios valores, que luego pueden ser asignados a variables
separadas.
def obtener_coordenadas():
x = 10
y = 20
return x, y

coordenada_x, coordenada_y = obtener_coordenadas()

Utilización en estructuras de datos inmutables: Las tuplas se pueden utilizar


como claves en diccionarios u otros elementos de estructuras de datos que
requieren objetos inmutables.
punto = (5, 10)
diccionario = {punto: "valor"}
Recuerda que, debido a que las tuplas son inmutables, no puedes agregar,
eliminar o modificar elementos después de haber sido creadas. Sin embargo,
puedes acceder a los elementos de una tupla utilizando índices, al igual que en
las listas.
Las tuplas son útiles cuando se necesita almacenar una colección de valores
que no cambiarán y se desea asegurar su integridad y evitar modificaciones
accidentales.
Con las tuplas utilizamos las siguientes funciones:
• len(): Retorna la longitud de una tupla, es decir, la cantidad de elementos
que contiene.
• index(): Retorna el índice de la primera aparición de un elemento
específico en la tupla.
• count(): Retorna la cantidad de veces que un elemento específico aparece
en la tupla.
• sorted(): Retorna una nueva tupla que contiene los elementos de la tupla
original, ordenados en orden ascendente.
• max(): Retorna el valor máximo de una tupla, considerando el orden de
los elementos.
• min(): Retorna el valor mínimo de una tupla, considerando el orden de los
elementos.

3
1.3. DICCIONARIOS
En Python, un diccionario es una estructura de datos que se utiliza para
almacenar una colección de pares clave-valor. A diferencia de las listas y tuplas,
los diccionarios no están ordenados y se accede a los valores utilizando sus
claves en lugar de índices.
Un diccionario es útil cuando se necesita almacenar y recuperar información
utilizando una clave única. Se utiliza en situaciones donde se requiere una
búsqueda rápida y eficiente de valores asociados a una clave. Algunos casos
comunes de uso de diccionarios incluyen:
• Almacenar datos relacionados: Un diccionario permite asociar valores a
claves, lo que es útil para representar relaciones y estructuras complejas.
• Búsquedas eficientes: Los diccionarios permiten acceder a los valores
rápidamente utilizando las claves como referencia, en lugar de tener que
recorrer una lista o realizar operaciones complejas de búsqueda.
• Configuraciones y opciones: Los diccionarios son útiles para almacenar
configuraciones y opciones en aplicaciones, ya que permiten acceder a
los valores mediante nombres descriptivos.
Para crear un diccionario en Python, se utilizan llaves {} y se separan los pares
clave-valor por comas. Aquí tienes un ejemplo de cómo crear un diccionario:
persona = {
"nombre": "Juan",
"edad": 30,
"ciudad": "Madrid"
}

Puedes acceder a los valores de un diccionario utilizando sus claves:


print(persona["nombre"]) # Imprime "Juan"
print(persona["edad"]) # Imprime 30

También puedes modificar los valores de un diccionario asignando nuevos


valores a las claves:
persona["edad"] = 35
print(persona["edad"]) # Imprime 35
Además, los diccionarios en Python tienen varios métodos incorporados que se
pueden utilizar para realizar operaciones comunes, como agregar pares clave-
valor, eliminar elementos, obtener listas de claves o valores, etc.

4
Aquí tienes algunos ejemplos de uso de diccionarios y sus métodos:
# Agregar un par clave-valor
persona["ocupacion"] = "Ingeniero"

# Eliminar un elemento del diccionario


del persona["ciudad"]

# Obtener una lista de claves


claves = persona.keys()
print(claves) # Imprime ["nombre", "edad", "ocupacion"]

# Obtener una lista de valores


valores = persona.values()
print(valores) # Imprime ["Juan", 35, "Ingeniero"]

Los diccionarios en Python son una poderosa herramienta para almacenar y


organizar datos de manera eficiente utilizando claves y valores. Puedes explorar
más funcionalidades y métodos de los diccionarios en la documentación oficial
de Python.
Con los diccionarios usamos las siguientes funciones:
• len(): Retorna la cantidad de pares clave-valor en el diccionario.
• keys(): Retorna una vista iterable de las claves del diccionario.
• values(): Retorna una vista iterable de los valores del diccionario.
• items(): Retorna una vista iterable de los pares clave-valor del diccionario.
• get(): Retorna el valor asociado a una clave especificada. Si la clave no
existe, retorna un valor predeterminado opcional en lugar de generar un
error.
• update(): Actualiza el diccionario con pares clave-valor de otro diccionario
o iterable.
• pop(): Elimina y retorna el valor asociado a una clave especificada. Si la
clave no existe, se puede proporcionar un valor predeterminado opcional.
• popitem(): Elimina y retorna un par clave-valor arbitrario del diccionario.
• clear(): Elimina todos los pares clave-valor del diccionario, dejándolo
vacío.
• copy(): Retorna una copia superficial (shallow copy) del diccionario.

1.4. CONJUNTOS

5
En Python, un conjunto (set) es una estructura de datos que se utiliza para
almacenar una colección desordenada de elementos únicos. Los conjuntos se
utilizan cuando se desea almacenar elementos sin duplicados y no se requiere
un orden específico.
Los conjuntos son útiles en varias situaciones, entre ellas:
• Eliminación de duplicados: Los conjuntos garantizan que no haya
elementos duplicados, lo que facilita la eliminación de duplicados de una
lista u otro iterable.
• Verificación de pertenencia: Los conjuntos ofrecen una búsqueda
eficiente de elementos, lo que permite verificar rápidamente si un
elemento está presente en el conjunto.
• Operaciones matemáticas de conjuntos: Los conjuntos en Python
soportan operaciones como intersección, unión, diferencia y diferencia
simétrica, lo que facilita las operaciones de conjuntos en matemáticas y
lógica.
Para crear un conjunto en Python, se utilizan llaves {} o la función set(). Los
elementos del conjunto se separan por comas. Ejemplo de cómo crear un
conjunto:
frutas = {"manzana", "banana", "naranja"}
También puedes crear un conjunto a partir de una lista o cualquier otro iterable
utilizando la función set():
numeros = set([1, 2, 3, 4, 5])
Una vez creado un conjunto, puedes realizar varias operaciones y utilizar
métodos para trabajar con él:
Agregar elementos: Utiliza el método add() para agregar un elemento al conjunto.
frutas.add("pera")
Eliminar elementos: Utiliza los métodos remove() o discard() para eliminar un
elemento del conjunto. La diferencia entre ellos es que remove() genera un error
si el elemento no está presente, mientras que discard() no genera ningún error.
frutas.remove("banana")
frutas.discard("manzana")

Verificar pertenencia: Utiliza la palabra clave in para verificar si un elemento está


presente en el conjunto.
if "naranja" in frutas:
print("La naranja está en el conjunto de frutas.")

6
Operaciones de conjuntos: Los conjuntos en Python tienen varios métodos para
realizar operaciones matemáticas, como unión, intersección, diferencia y
diferencia simétrica. Estos métodos incluyen union(), intersection(), difference()
y symmetric_difference().
frutas_2 = {"pera", "durazno", "manzana"}

union_frutas = frutas.union(frutas_2)
interseccion_frutas = frutas.intersection(frutas_2)
diferencia_frutas = frutas.difference(frutas_2)
diferencia_simetrica_frutas =
frutas.symmetric_difference(frutas_2)

Recuerda que los conjuntos no mantienen un orden específico de los elementos


y no permiten elementos duplicados. Estas características los hacen útiles en
muchas situaciones donde se necesita almacenar elementos únicos y realizar
operaciones eficientes de conjuntos.
Con los conjuntos utilizamos las siguientes funciones:
• add(elemento): Agrega un elemento al conjunto.
• remove(elemento): Remueve un elemento específico del conjunto. Si el
elemento no está presente, genera un error.
• discard(elemento): Remueve un elemento del conjunto si está presente.
No genera un error si el elemento no existe.
• pop(): Remueve y retorna un elemento arbitrario del conjunto.
• clear(): Remueve todos los elementos del conjunto, dejándolo vacío.
• copy(): Retorna una copia superficial (shallow copy) del conjunto.
• len(): Retorna la cantidad de elementos en el conjunto.
• in: Verifica si un elemento está presente en el conjunto.
• union(conjunto): Retorna un nuevo conjunto que es la unión de dos
conjuntos.
• intersection(conjunto): Retorna un nuevo conjunto que es la intersección
de dos conjuntos.
• difference(conjunto): Retorna un nuevo conjunto que contiene los
elementos del primer conjunto que no están en el segundo conjunto.
• symmetric_difference(conjunto): Retorna un nuevo conjunto que contiene
los elementos que están en uno de los conjuntos, pero no en ambos.

1.5. PILAS
En Python, una pila (stack) es una estructura de datos que sigue el principio de
"último en entrar, primero en salir" (LIFO, por sus siglas en inglés Last-In, First-
Out). Se utiliza para almacenar elementos donde el último elemento agregado
es el primero en ser retirado.
7
La pila se utiliza para resolver problemas que implican un seguimiento temporal
o jerarquía de elementos, como el manejo de llamadas a funciones, el rastreo de
operaciones en la recursión, la evaluación de expresiones postfix (notación
polaca inversa), entre otros.
En Python, puedes implementar una pila utilizando una lista. Ejemplo de cómo
crear una pila y realizar operaciones básicas en ella:
pila = [] # Crear una pila vacía

pila.append(1) # Agregar elementos a la pila


pila.append(2)
pila.append(3)
print(pila) # Imprimir la pila: [1, 2, 3]
elemento = pila.pop() # Retirar el último elemento de la
pila
print(elemento) # Imprimir el elemento retirado: 3
print(pila) # Imprimir la pila actualizada: [1, 2]

En el ejemplo anterior, utilizamos la función append() para agregar elementos a


la pila y la función pop() para retirar el último elemento agregado. Al retirar un
elemento, se elimina de la pila y se devuelve su valor. El resultado es una pila
que se va actualizando a medida que se agregan y retiran elementos.
La principal razón para utilizar una pila es cuando necesitamos manejar
elementos en el orden LIFO. Algunos casos de uso comunes de las pilas
incluyen:
• Implementación de algoritmos como el recorrido en profundidad (DFS, por
sus siglas en inglés Depth-First Search) en grafos y árboles.
• Evaluación de expresiones postfix (notación polaca inversa) en
matemáticas y programación.
• Manejo de llamadas a funciones y rastreo de operaciones en la recursión.
• Administración de la navegación y el historial de páginas en aplicaciones
web.
Recuerda que en Python, las pilas se pueden implementar utilizando listas, pero
también existen implementaciones más especializadas de pilas en el módulo
collections de Python, como deque, que ofrecen una mejor eficiencia en ciertos
casos.
1.6. COLAS

8
En Python, una cola (queue) es una estructura de datos que sigue el principio de
"primero en entrar, primero en salir" (FIFO, por sus siglas en inglés First-In, First-
Out). Se utiliza para almacenar elementos donde el primer elemento agregado
es el primero en ser retirado.
La cola se utiliza en situaciones donde es importante mantener el orden de
llegada de los elementos, como en la gestión de tareas, la planificación de
procesos, el manejo de solicitudes en un servidor, etc.
En Python podemos implementar una cola utilizando la lista estándar y sus
operaciones. Ejemplo de cómo crear una cola y realizar operaciones básicas en
ella sin importar ningún módulo adicional:
cola = [] # Crear una cola vacía
cola.append(1) # Agregar elementos a la cola
cola.append(2)
cola.append(3)
print(cola) # Imprimir la cola: [1, 2, 3]
elemento = cola.pop(0) # Obtener y retirar el primer
elemento de la cola
print(elemento) # Imprimir el elemento obtenido: 1
print(cola) # Imprimir la cola actualizada: [2, 3]
En este caso, utilizamos una lista (cola) para representar la cola. La función
append() se utiliza para agregar elementos a la cola al final de la lista, y la función
pop(0) se utiliza para obtener y retirar el primer elemento de la cola.
Sin embargo, es importante tener en cuenta que utilizar una lista estándar para
implementar una cola puede no ser tan eficiente en términos de tiempo de
ejecución, especialmente si la cola es grande y se realizan operaciones
frecuentes de inserción y eliminación en la parte delantera de la lista. En esos
casos, la clase Queue del módulo queue o una implementación especializada
como deque del módulo collections proporcionan una mejor eficiencia y
funcionalidad incorporada para trabajar con colas.
Por lo tanto, si necesitas una implementación más eficiente o requieres
funcionalidades adicionales, se recomienda utilizar la clase Queue del módulo
queue o deque del módulo collections.

9
1. MANEJO DE ARCHIVOS
En el desarrollo de software solemos utilizar archivos por diferentes causas:
• Almacenamiento persistente de datos: Los archivos permiten almacenar
datos de forma persistente en el sistema de archivos. Esto significa que
los datos no se pierden cuando se cierra el programa y se pueden acceder
nuevamente en futuras ejecuciones.
• Lectura y escritura de datos: Los archivos ofrecen la capacidad de leer y
escribir datos de manera eficiente. Puedes leer información desde un
archivo existente para utilizarla en tu programa o escribir datos generados
o procesados por tu programa en un archivo para su posterior uso.
• Manejo de grandes volúmenes de datos: Si tienes grandes cantidades de
datos que no pueden almacenarse en memoria, los archivos proporcionan
una forma de trabajar con esos datos en partes, leyendo o escribiendo
bloques más pequeños a medida que sea necesario.
• Comunicación con otros programas: Los archivos pueden utilizarse como
medio de comunicación entre diferentes programas. Por ejemplo, un
programa puede generar un archivo de salida que luego es utilizado por
otro programa para procesar esa información.
• Almacenamiento y carga de configuraciones: Los archivos son útiles para
almacenar configuraciones de programas. Puedes utilizar archivos de
texto estructurados como archivos de configuración para personalizar el
comportamiento de tu programa sin necesidad de modificar el código
fuente.
• Procesamiento de archivos de texto estructurados: Si trabajas con
archivos de texto estructurados, como archivos CSV, archivos de registro
(logs) o archivos de texto plano con un formato específico, puedes utilizar
Python para leer y analizar fácilmente estos archivos, extraer la
información relevante y realizar operaciones o cálculos sobre los datos.

2. Tipos de archivos
Python te permite abrir diferentes tipos de archivos, como:
• Archivos de texto (.txt, .csv, .log, etc.): Son archivos que contienen texto
legible.
• Archivos binarios (.jpg, .mp3, .pdf, etc.): Son archivos que contienen datos
en un formato binario específico.
• Archivos JSON (.json): Son archivos que almacenan datos en formato
JSON.
• Archivos XML (.xml): Son archivos que almacenan datos en formato XML.
• Archivos de hojas de cálculo (.xlsx, .xls): Son archivos utilizados para
almacenar datos en forma tabular.
• Archivos de bases de datos (.db, .sqlite): Son archivos utilizados para
almacenar datos estructurados en una base de datos.

1
3. Apertura de archivos
Para abrir un archivo en Python, puedes utilizar la función open(). La sintaxis
básica para abrir un archivo es la siguiente:
archivo = open('nombre_archivo', 'modo')
Donde:
nombre_archivo es el nombre o la ruta del archivo que deseas abrir.
modo especifica el modo de apertura del archivo, que puede ser 'r' para lectura
(por defecto), 'w' para escritura, 'a' para agregar contenido al final del archivo, o
'x' para crear un archivo nuevo y escribir en él. Además, puedes agregar 'b' al
modo para abrir el archivo en modo binario, por ejemplo, 'rb' para lectura binaria.
Una vez abierto el archivo, puedes realizar diferentes operaciones según el modo
de apertura:
• Modo de lectura ('r'): Puedes leer el contenido del archivo utilizando
métodos como read(), readline() o readlines().
• Modo de escritura ('w'): Puedes escribir en el archivo utilizando el método
write().
• Modo de agregar ('a'): Puedes agregar contenido al final del archivo
utilizando el método write().
Es importante cerrar el archivo después de haber terminado de trabajar con él
para liberar los recursos del sistema utilizando el método close(), por ejemplo:
archivo.close().
Ejemplo de apertura de un archivo en modo de lectura:
archivo = open('archivo.txt', 'r')
contenido = archivo.read()
print(contenido)
archivo.close()

Es importante tener en cuenta que a partir de Python 3.6, se recomienda utilizar


el bloque with para abrir archivos, ya que se encarga automáticamente de cerrar
el archivo una vez que se sale del bloque, incluso si ocurren excepciones. Por
ejemplo:
with open('archivo.txt', 'r') as archivo:
contenido = archivo.read()
print(contenido)
El uso del bloque with hace que el cierre del archivo sea más seguro y simplifica
el código.
Ejemplo:

2
# Abrir el archivo de entrada en modo de lectura
with open('entrada.txt', 'r') as archivo_entrada:
# Abrir el archivo de salida en modo de escritura
with open('salida.txt', 'w') as archivo_salida:
# Leer el contenido línea por línea
for linea in archivo_entrada:
# Realizar operaciones con cada línea
palabras = linea.split() # Dividir la línea en
palabras
num_palabras = len(palabras) # Contar el número
de palabras
resultado = f"Línea: {linea.strip()} - Número de
palabras: {num_palabras}"

# Escribir el resultado en el archivo de salida


archivo_salida.write(resultado + '\n')

# Imprimir un mensaje de éxito


print("Operación completada con éxito. Se ha generado el
archivo de salida.")

4. Lectura de archivos
Lectura línea por línea:
Puedes utilizar un bucle for para leer el archivo línea por línea. Esto es útil cuando
deseas procesar el archivo línea por línea sin cargar todo el contenido en
memoria de una vez.
with open('archivo.txt', 'r') as archivo:
for linea in archivo:
# Procesar cada línea
print(linea)

Lectura de todo el contenido:


Puedes utilizar el método read() para leer todo el contenido del archivo en una
sola cadena. Esto es útil cuando deseas tener el contenido completo del archivo
en memoria para manipularlo.
3
with open('archivo.txt', 'r') as archivo:
contenido = archivo.read()
# Procesar el contenido completo
print(contenido)
Lectura de líneas específicas:
Puedes utilizar el método readlines() para leer todas las líneas del archivo y
almacenarlas en una lista. Luego, puedes acceder a líneas específicas utilizando
los índices de la lista.
with open('archivo.txt', 'r') as archivo:
lineas = archivo.readlines()
# Acceder a líneas específicas
print(lineas[0]) # Primera línea
print(lineas[2]) # Tercera línea

5. Escritura de archivos
En Python, puedes escribir en un archivo utilizando la función write() o el método
writelines(). A continuación, te muestro ejemplos de ambos métodos:
Escribir un archivo línea por línea utilizando write():
Puedes utilizar el método write() para escribir una línea a la vez en un archivo.
Asegúrate de incluir los caracteres de nueva línea (\n) al final de cada línea si
deseas separarlas.
with open('archivo.txt', 'w') as archivo:
archivo.write('Línea 1\n')
archivo.write('Línea 2\n')
archivo.write('Línea 3\n')
Escribir múltiples líneas utilizando writelines():
Puedes utilizar el método writelines() para escribir varias líneas a la vez en un
archivo. Este método acepta una lista de cadenas, donde cada cadena
representa una línea.
lineas = ['Línea 1\n', 'Línea 2\n', 'Línea 3\n']

with open('archivo.txt', 'w') as archivo:


archivo.writelines(lineas)

4
Recuerda que al abrir el archivo en modo de escritura ('w'), si el archivo ya existe,
se sobrescribirá. Si deseas agregar contenido al final del archivo sin
sobrescribirlo, puedes utilizar el modo de apertura 'a' en lugar de 'w'.
Es importante cerrar el archivo después de escribir para asegurarte de que los
cambios se guarden correctamente. Al utilizar la declaración with open() as
archivo, el archivo se cerrará automáticamente al salir del bloque with.
Estos son solo ejemplos básicos de cómo escribir en un archivo en Python.
Puedes adaptar estos métodos según tus necesidades, concatenar variables,
generar contenido dinámico, entre otros.
6. Archivos binarios
Un archivo binario es un tipo de archivo que almacena datos en una
representación binaria, es decir, en forma de secuencias de unos y ceros. A
diferencia de los archivos de texto, que almacenan caracteres legibles por
humanos, los archivos binarios almacenan información en su forma más básica,
sin ninguna interpretación directa.
En un archivo binario, los datos se organizan en estructuras de bits, bytes y
patrones específicos que representan diferentes tipos de información, como
números enteros, números de punto flotante, caracteres, imágenes, sonidos,
videos, entre otros. Estos archivos se utilizan comúnmente para almacenar
información compleja y detallada que no se puede representar fácilmente en
formato de texto.
Los archivos binarios pueden contener cualquier tipo de información y no están
limitados a ningún formato específico. Algunos ejemplos de archivos binarios
comunes incluyen archivos de imágenes (como JPEG, PNG), archivos de audio
(como MP3, WAV), archivos ejecutables (como EXE, DLL), archivos de bases de
datos y archivos comprimidos (como ZIP, RAR).
Para trabajar con archivos binarios en Python, puedes utilizar los modos de
apertura 'rb' para lectura y 'wb' para escritura. Ejemplo: leer y escribir archivos
binarios en Python:
Lectura de archivos binarios:
Abre el archivo en modo de lectura binaria utilizando el modo 'rb'.
Utiliza el método read() para leer todo el contenido binario del archivo.
Procesa los datos leídos según tus necesidades.
Ejemplo de lectura de un archivo binario:
with open('archivo.bin', 'rb') as archivo:
contenido_binario = archivo.read()
# Procesa los datos binarios según tus necesidades

Escritura en archivos binarios:

5
Abre el archivo en modo de escritura binaria utilizando el modo 'wb'.
Utiliza el método write() para escribir datos binarios en el archivo.
Aquí tienes un ejemplo de escritura en un archivo binario:
datos_binarios = b'\x00\x01\x02\x03' # Ejemplo de datos
binarios
with open('archivo.bin', 'wb') as archivo:
archivo.write(datos_binarios)
Es importante recordar que al trabajar con archivos binarios, los datos se
manejan en su representación binaria directa, lo que significa que debes
asegurarte de utilizar los métodos y formatos de datos adecuados para leer y
escribir correctamente la información en el archivo.
Además, ten en cuenta que al utilizar archivos binarios, los datos no se pueden
leer o interpretar directamente como texto. Por lo tanto, es posible que necesites
realizar conversiones o manipulaciones adicionales según el formato o
estructura de los datos binarios que estés manejando.

7. Archivos CSV
Un archivo CSV (Comma-Separated Values) es un tipo de archivo que se utiliza
para almacenar datos tabulares en forma de texto plano. Como su nombre lo
indica, los datos en un archivo CSV se separan por comas (u otro delimitador)
para organizar la información en columnas y filas.
Cada línea del archivo CSV representa una fila de datos, y los valores de cada
columna se separan por el delimitador, que suele ser una coma. Por ejemplo, un
archivo CSV que almacena información de empleados podría tener la siguiente
estructura:
Nombre,Apellido,Edad,Departamento
Juan,Pérez,35,Ventas
María,Gómez,42,Recursos Humanos
Python proporciona varias formas de trabajar con archivos CSV. Una de las
formas más comunes es utilizando el módulo csv incorporado en la biblioteca
estándar de Python. Con este módulo, puedes leer y escribir archivos CSV de
manera sencilla.
Aquí tienes un ejemplo básico de cómo leer un archivo CSV en Python utilizando
el módulo csv:

import csv
6
# Abrir el archivo CSV en modo lectura
with open('datos.csv', 'r') as archivo_csv:
# Crear un lector de CSV
lector_csv = csv.reader(archivo_csv)

# Leer los datos línea por línea


for fila in lector_csv:
# Acceder a los valores de cada columna
nombre = fila[0]
apellido = fila[1]
edad = fila[2]
departamento = fila[3]

# Hacer algo con los datos...


Del mismo modo, puedes utilizar el módulo csv para escribir datos en un archivo
CSV. Aquí tienes un ejemplo:
import csv

# Datos a escribir en el archivo CSV


datos = [
['Juan', 'Pérez', 35, 'Ventas'],
['María', 'Gómez', 42, 'Recursos Humanos']
]

# Abrir el archivo CSV en modo escritura


with open('datos.csv', 'w', newline='') as archivo_csv:
# Crear un escritor de CSV
escritor_csv = csv.writer(archivo_csv)

# Escribir los datos fila por fila

7
for fila in datos:
escritor_csv.writerow(fila)

8. Directorios
Para acceder a los directorios donde se encuentran los archivos de manera
independiente del sistema operativo utilizado, puedes utilizar el módulo os de
Python. El módulo os proporciona funciones y métodos para interactuar con el
sistema operativo, incluyendo la manipulación de rutas de archivos y directorios.
Aquí tienes algunas funciones y métodos útiles del módulo os para trabajar con
directorios:
• os.getcwd(): Devuelve la ruta del directorio de trabajo actual.
• os.chdir(ruta): Cambia el directorio de trabajo actual a la ruta especificada.
• os.listdir(ruta): Devuelve una lista con los nombres de los archivos y
directorios en la ruta especificada.
• os.path.join(ruta1, ruta2): Combina dos rutas para formar una nueva ruta.
• os.path.exists(ruta): Verifica si la ruta especificada existe.
• os.path.isdir(ruta): Verifica si la ruta especificada es un directorio.
Aquí tienes un ejemplo que muestra cómo obtener los nombres de los archivos
en un directorio específico:
import os

# Obtener la ruta del directorio actual


directorio_actual = os.getcwd()

# Obtener la lista de nombres de archivos en el directorio


actual
archivos = os.listdir(directorio_actual)

# Imprimir los nombres de los archivos


for archivo in archivos:
print(archivo)
Ten en cuenta que el comportamiento exacto puede variar según el sistema
operativo utilizado. Sin embargo, utilizando las funciones y métodos
proporcionados por el módulo os, puedes escribir código que sea independiente
del sistema operativo y funcione correctamente en diferentes plataformas.

8
1. MANEJO DE ERRORES
Al programar en Python, puedes cometer varios tipos de errores. Aquí tienes una
lista de los errores más comunes:
• Errores de sintaxis: Estos errores ocurren cuando el código no sigue la
estructura y reglas de sintaxis de Python. Pueden incluir olvidar dos
puntos (:) al definir un bucle o una función, olvidar cerrar paréntesis o
comillas, entre otros.
• Errores de tiempo de ejecución: Estos errores ocurren durante la
ejecución del programa y generalmente se deben a problemas lógicos o
a datos inesperados. Algunos ejemplos comunes incluyen divisiones por
cero, índices fuera de rango, errores de conversión de tipos, etc.
• Errores lógicos: Estos errores ocurren cuando la lógica del programa es
incorrecta y no produce los resultados esperados. Puede deberse a una
mala comprensión del problema, mal uso de condiciones, bucles o
variables, o errores en algoritmos y cálculos.
• Errores de nombre de variable: Estos errores ocurren cuando intentas
usar una variable que no ha sido definida previamente o cuando el nombre
de la variable está mal escrito. Python tratará de interpretarla como una
nueva variable y generará un error.
• Errores de importación: Estos errores ocurren cuando intentas importar
un módulo o una función que no existe o que no está disponible en tu
entorno de Python. También pueden ocurrir si hay errores en la estructura
del código del módulo que intentas importar.
• Errores de archivo: Estos errores ocurren cuando hay problemas al abrir,
leer o escribir archivos. Puede ser debido a que el archivo no existe, no
tienes los permisos necesarios o hay problemas de formato de archivo.
• Errores de lógica de programación: Estos errores son más difíciles de
detectar y pueden ocurrir cuando la lógica detrás del programa es
incorrecta o incompleta. El programa puede ejecutarse sin generar
errores, pero los resultados no serán los esperados.

2. EXCEPCIONES
En programación, una excepción es un evento que ocurre durante la ejecución
de un programa y interrumpe el flujo normal de ejecución. Las excepciones
generalmente se generan cuando ocurren situaciones inesperadas o errores que
el programa no puede manejar automáticamente.
Las excepciones son útiles porque permiten identificar y manejar errores de
manera controlada. En lugar de que el programa se bloquee por completo
cuando ocurre un error, las excepciones brindan una forma de detectar y
responder a errores de manera específica, evitando que el programa se detenga
abruptamente.
2.1. MANEJO DE EXCEPCIONES

1
En Python, el manejo de excepciones se realiza utilizando los bloques try, except,
else y finally.
try y except: Estos bloques se utilizan en conjunto para capturar y manejar
excepciones específicas. El código que potencialmente puede generar una
excepción se coloca dentro del bloque try, y si ocurre una excepción, se captura
en el bloque except.
Ejemplo:
try:
numero = int(input("Ingrese un número: "))
resultado = 10 / numero
print("El resultado es:", resultado)
except ValueError:
print("Error: Ingrese un número válido.")
except ZeroDivisionError:
print("Error: No se puede dividir entre cero.")

En este ejemplo, el bloque try intenta realizar una división y captura las
excepciones ValueError y ZeroDivisionError de manera específica. Si se ingresa
un valor no numérico, se ejecutará el bloque except ValueError. Si se intenta
dividir entre cero, se ejecutará el bloque except ZeroDivisionError.
else: Este bloque se ejecuta si no se produce ninguna excepción en el bloque
try. Puedes usarlo para ejecutar código adicional después de que se haya
ejecutado el bloque try correctamente.
try:
numero = int(input("Ingrese un número: "))
resultado = 10 / numero
except ValueError:
print("Error: Ingrese un número válido.")
except ZeroDivisionError:
print("Error: No se puede dividir entre cero.")
else:
print("El resultado es:", resultado)

En este caso, si se ingresa un valor no numérico o se intenta dividir entre cero,


se ejecutarán los bloques except. Pero si no se produce ninguna excepción, se
ejecutará el bloque else y se imprimirá el resultado.

2
finally: Este bloque se ejecuta siempre, independientemente de si se produce
una excepción o no. Se utiliza para realizar tareas de limpieza o liberar recursos,
como cerrar archivos o conexiones a bases de datos.
try:
archivo = open("datos.txt", "r")
# Realizar operaciones con el archivo
except FileNotFoundError:
print("Error: Archivo no encontrado.")
finally:
archivo.close()

En este ejemplo, el bloque finally se asegura de que el archivo se cierre


correctamente, incluso si se produce una excepción o no. Esto evita dejar
archivos abiertos accidentalmente y garantiza una liberación adecuada de
recursos.
Se pueden combinar los bloques except, else y finally según las necesidades y
manejar diferentes tipos de excepciones de manera específica.
2.2. PROCESAMIENTO Y PROPAGACIÓN DE EXCEPCIONES
Cuando se genera una excepción en un bloque de código, el flujo normal de
ejecución se interrumpe y el control se transfiere al bloque except
correspondiente para manejar la excepción. Sin embargo, si no se encuentra un
bloque except adecuado dentro del mismo bloque try, la excepción se propaga
al bloque try exterior o a niveles superiores en la pila de llamadas hasta que se
encuentre un bloque except que pueda manejarla o, en caso contrario, el
programa se detiene y muestra un rastreo de la excepción.
Ejemplo:
def funcion_b():
resultado = 10 / 0 # División por cero
def funcion_a():
funcion_b()

try:
funcion_a()
except ZeroDivisionError:
print("Error: División por cero")

3
En este ejemplo, se llama a la función funcion_a(), que a su vez llama a
funcion_b(). Dentro de funcion_b(), se realiza una división por cero, lo que genera
una excepción ZeroDivisionError. Dado que no hay un bloque try-except dentro
de funcion_b(), la excepción se propaga hacia el bloque try en funcion_a(), donde
se encuentra un bloque except adecuado para manejarla. Como resultado, se
imprime el mensaje "Error: División por cero".
El proceso de propagación de excepciones permite que las excepciones se
manejen en diferentes niveles del programa, lo que proporciona una forma
efectiva de controlar y responder a las situaciones de error en el código.
Es importante tener en cuenta que si una excepción se propaga hasta el nivel
superior sin ser capturada, el programa se detendrá y mostrará un rastreo de la
excepción, que incluye información sobre la excepción y la secuencia de
llamadas de funciones que la llevaron a ser propagada. Este rastreo es útil para
depurar y comprender qué causó la excepción.
Además, puedes utilizar la palabra clave raise para generar manualmente una
excepción en cualquier parte de tu código. Esto puede ser útil cuando deseas
indicar una condición de error específica y controlar cómo se maneja.
Espero que esta explicación aclare cómo funciona el procesamiento y la
propagación de excepciones en Python. Si tienes más preguntas, no dudes en
hacerlas.
2.3. RAISE
La palabra clave raise en Python se utiliza para generar manualmente una
excepción en un punto específico del código. Esto te permite indicar que se ha
producido una condición de error o excepción personalizada y controlar cómo se
maneja.
La sintaxis básica para usar raise es la siguiente:
raise TipoDeExcepcion("Mensaje de error")

Donde TipoDeExcepcion es el tipo de excepción que deseas generar y "Mensaje


de error" es un mensaje descriptivo opcional que puedes incluir para
proporcionar más información sobre la excepción.
Ejemplo:
def dividir(a, b):
if b == 0:
raise ZeroDivisionError("No se puede dividir entre
cero")
return a / b

try:

4
resultado = dividir(10, 0)
except ZeroDivisionError as e:
print("Error:", str(e))

En este ejemplo, la función dividir() comprueba si el divisor b es cero. Si es cero,


se genera manualmente una excepción ZeroDivisionError utilizando la palabra
clave raise y se proporciona un mensaje de error personalizado. Luego, se
captura la excepción con el bloque except y se imprime el mensaje de error.
Puedes utilizar raise para generar excepciones de cualquier tipo, ya sea las
excepciones incorporadas en Python, como ValueError, TypeError, etc., o incluso
puedes crear tus propias excepciones personalizadas creando una clase de
excepción.
Ejemplo:
class MiExcepcion(Exception):
pass

def mi_funcion():
raise MiExcepcion("Ocurrió un error personalizado")

try:
mi_funcion()
except MiExcepcion as e:
print("Error:", str(e))

En este ejemplo, se crea una clase de excepción personalizada llamada


MiExcepcion que hereda de la clase base Exception. Luego, dentro de la función
mi_funcion(), se genera manualmente una instancia de MiExcepcion utilizando
raise. Posteriormente, se captura la excepción con el bloque except y se imprime
el mensaje de error.
La palabra clave raise te brinda flexibilidad para generar y controlar excepciones
de manera explícita en tu código, permitiéndote señalar condiciones de error
específicas y manejarlas de acuerdo a tus necesidades.

3. VALIDACIONES
En Python, las validaciones son mecanismos utilizados para verificar si ciertas
condiciones se cumplen en un programa. Se utilizan para garantizar que los
datos o las suposiciones sean correctos antes de continuar con la ejecución del
código.

5
Una forma común de realizar validaciones en Python es mediante la declaración
if. Puedes usar condiciones if para verificar una expresión y ejecutar un bloque
de código si la condición es verdadera. Ejemplo:
def dividir(a, b):
if b != 0:
resultado = a / b
return resultado
else:
print("Error: No se puede dividir entre cero")

resultado = dividir(10, 5)
if resultado is not None:
print("El resultado de la división es:", resultado)

En este ejemplo, la función dividir() verifica si el divisor b es diferente de cero


antes de realizar la división. Si b es cero, se imprime un mensaje de error.
Después de llamar a la función dividir(), se verifica si el resultado es diferente de
None antes de imprimirlo.
Otra forma de hacer validaciones en Python es utilizando la declaración assert.
La declaración assert se utiliza para verificar que una expresión sea verdadera
y, si no lo es, genera una excepción AssertionError. Ejemplo:
def dividir(a, b):
assert b != 0, "Error: No se puede dividir entre cero"
resultado = a / b
return resultado

resultado = dividir(10, 5)
print("El resultado de la división es:", resultado)

En este ejemplo, la expresión b != 0 se verifica utilizando la declaración assert.


Si la expresión es falsa, se genera una excepción AssertionError con el mensaje
de error especificado. Si la expresión es verdadera, la ejecución continúa
normalmente y se realiza la división.

6
Es importante tener en cuenta que las declaraciones assert se utilizan
principalmente para detectar errores de programación y no para manejar errores
esperados o condiciones excepcionales. Por lo general, se utilizan durante el
desarrollo y las pruebas, y se recomienda desactivarlas en entornos de
producción.
En resumen, las validaciones en Python se realizan utilizando declaraciones if
para verificar condiciones y ejecutar código en consecuencia. La declaración
assert se utiliza para verificar expresiones y generar una excepción si la
expresión es falsa.
3.1. VALIDACIONES ENTRADA y TIPOS DE DATOS
La validación de datos de entrada del usuario y de tipos es una parte importante
de cualquier programa para garantizar que los datos ingresados sean correctos
y cumplan con los requisitos esperados. Aquí te presento algunas técnicas
comunes para validar los datos de entrada en Python:
Validación de tipos de datos:
type(): Puedes utilizar la función type() para verificar el tipo de dato de una
variable. Por ejemplo:
edad = input("Ingrese su edad: ")
if type(edad) != int:
print("Error: La edad debe ser un número entero")

isinstance(): La función isinstance() permite verificar si un objeto es una instancia


de una clase o de una clase derivada. Por ejemplo:
numero = input("Ingrese un número: ")
if not isinstance(numero, int):
print("Error: Debe ingresar un número entero")

Validación de rangos:
Puedes verificar si un valor se encuentra dentro de un rango específico utilizando
operadores de comparación, como > (mayor que), < (menor que), >= (mayor o
igual que), <= (menor o igual que), etc. Por ejemplo:
edad = int(input("Ingrese su edad: "))
if edad < 0 or edad > 120:
print("Error: La edad debe estar entre 0 y 120")

Validación de formatos:
Puedes utilizar expresiones regulares para validar cadenas de texto según un
formato específico. El módulo re de Python proporciona funciones para trabajar
con expresiones regulares. Por ejemplo, para validar un número de teléfono en
un formato determinado:
7
import re
telefono = input("Ingrese su número de teléfono: ")
patron = r"\d{3}-\d{3}-\d{4}"
if not re.match(patron, telefono):
print("Error: El número de teléfono debe tener el formato
XXX-XXX-XXXX")

Estos son solo algunos ejemplos básicos de validación de datos en Python. La


elección de la técnica de validación depende de los requisitos específicos de tu
programa y del tipo de datos que estés validando.
Recuerda que la validación de datos es una capa adicional de seguridad y
control, pero no es suficiente por sí sola. También es importante considerar otras
formas de manejo de errores, como el manejo de excepciones, para garantizar
un comportamiento adecuado del programa en situaciones inesperadas.

8
1. MODULOS
Un módulo en Python es un archivo que contiene código reutilizable. Estos
módulos se utilizan para organizar y estructurar el código de manera más
efectiva, facilitando la reutilización y el mantenimiento del mismo. Algunas
ventajas de usar módulos en Python son:
• Organización del código: Los módulos permiten organizar el código en
unidades lógicas y separadas. Puedes agrupar funciones, clases y
variables relacionadas en un solo archivo, lo que hace que el código sea
más legible y fácil de entender.
• Reutilización de código: Al dividir el código en módulos, puedes reutilizar
funciones, clases y variables en diferentes programas. Esto evita la
duplicación de código y facilita la implementación de la misma
funcionalidad en diferentes partes de tu proyecto.
• Mantenibilidad: Los módulos permiten separar diferentes componentes de
un programa, lo que facilita la identificación y corrección de errores.
Además, si necesitas realizar cambios en una parte específica del código,
solo tienes que modificar el módulo correspondiente, sin afectar el resto
del programa.
• Modularidad: Los módulos promueven la modularidad en el diseño de
programas. Puedes pensar en cada módulo como una "caja negra" que
encapsula su funcionalidad y proporciona una interfaz clara y definida
para interactuar con él. Esto facilita la colaboración en equipos de
desarrollo y permite dividir proyectos grandes en módulos más pequeños
y manejables.
• Espacio de nombres (namespace) separado: Cada módulo en Python
tiene su propio espacio de nombres, lo que significa que las variables,
funciones y clases definidas en un módulo no entran en conflicto con los
nombres definidos en otros módulos. Esto ayuda a evitar colisiones de
nombres y proporciona un mejor control y organización del código.
• Módulos estándar y externos: Python ofrece una amplia biblioteca
estándar que incluye una variedad de módulos para realizar tareas
comunes, como manipulación de archivos, acceso a bases de datos,
generación de números aleatorios, entre otros. Además, la comunidad de
Python ha creado una gran cantidad de módulos externos que puedes
instalar y utilizar para ampliar las capacidades de Python en diferentes
áreas.
Al utilizar módulos, puedes aprovechar el código existente, modularizar tu
programa en partes más pequeñas y fáciles de mantener, y acceder a
funcionalidades adicionales proporcionadas por módulos externos. Esto ayuda a
mejorar la eficiencia y la productividad en el desarrollo de software.

2. CREACION y USO DE MODULOS

1
Para crear un moudlo necesitamos abrir un nuevo archivo en un editor de texto
o entorno de desarrollo integrado (IDE) y guardarlo con una extensión .py. Por
ejemplo, llamarlo mi_modulo.py.
Dentro del archivo mi_modulo.py, definir las funciones, clases, variables y
cualquier otro código que desees incluir en tu módulo. Por ejemplo:
# mi_modulo.py
def saludar(nombre):
print("Hola,", nombre)
def despedir(nombre):
print("Adiós,", nombre)
pi = 3.14159

En otro archivo o en la consola interactiva de Python, utilizar el módulo


mi_modulo importándolo. Por ejemplo:
# Importar el módulo completo
import mi_modulo

mi_modulo.saludar("Juan") # Salida: Hola, Juan


mi_modulo.despedir("Juan") # Salida: Adiós, Juan
print(mi_modulo.pi) # Salida: 3.14159

En este ejemplo, hemos importado el módulo mi_modulo utilizando la


declaración import. Luego, hemos utilizado las funciones saludar() y despedir()
del módulo, así como la variable pi.
También puedes importar funciones o variables específicas del módulo utilizando
la forma de importación from. Por ejemplo:
# Importar funciones/variables específicas del módulo
from mi_modulo import saludar, pi
saludar("María") # Salida: Hola, María
print(pi) # Salida: 3.14159

Recuerda que el archivo mi_modulo.py debe estar en el mismo directorio o en


una ruta de búsqueda especificada por la variable de entorno PYTHONPATH
para que pueda ser encontrado y utilizado correctamente.

3. EJECUCION DE MODULOS

2
Para ejecutar un modulo como script, tenemos que añadir un bloque condicional
utilizando la variable global __name__ para comprobar si el módulo se está
ejecutando como un script. Por ejemplo:

# mi_modulo.py

def saludar(nombre):
print("Hola,", nombre)

def despedir(nombre):
print("Adiós,", nombre)

pi = 3.14159

if __name__ == "__main__":
nombre = input("Ingresa tu nombre: ")
saludar(nombre)
despedir(nombre)

Luego debemos guardar el archivo.

Para ejecutar el módulo como un script:

Tenemos que abrir una terminal o línea de comandos.

Navegar al directorio donde se encuentra el archivo mi_modulo.py.

Ejecutar el siguiente comando:


python mi_modulo.py

Esto ejecutará el módulo como un script independiente y se mostrará el mensaje


"Ingresa tu nombre:". Puedes ingresar un nombre y presionar Enter para ver los
saludos correspondientes.

3
Al utilizar el bloque condicional if __name__ == "__main__":, te aseguras de que
el código dentro de ese bloque solo se ejecute cuando el módulo se ejecuta como
un script independiente. Si el módulo se importa desde otro archivo, el bloque no
se ejecutará automáticamente.
4. BIBLIOTECAS DE MODULOS
Python cuenta con una amplia biblioteca estándar que proporciona una serie de
módulos listos para usar en tus programas. Algunas de las bibliotecas de
módulos estándar más comunes y útiles de Python incluyen:
• os: Proporciona funciones para interactuar con el sistema operativo, como
manipular archivos y directorios, acceder a variables de entorno y ejecutar
comandos del sistema.
• sys: Contiene funciones y variables que interactúan con el intérprete de
Python. Puede utilizarse para acceder a argumentos de línea de
comandos, manipular la ruta de búsqueda de módulos y otras
operaciones relacionadas con el intérprete.
• math: Ofrece funciones matemáticas y constantes, como operaciones
trigonométricas, exponenciales, logarítmicas y funciones especiales.
• datetime: Proporciona clases y funciones para trabajar con fechas, horas
y manipulación de tiempo. Permite realizar operaciones como cálculos de
diferencia de tiempo, formato de fecha y hora, y conversiones entre
diferentes formatos.
• random: Permite generar números aleatorios y realizar operaciones
relacionadas con aleatoriedad, como mezclar listas, seleccionar
elementos aleatorios y generar secuencias aleatorias.
• json: Proporciona funciones para trabajar con el formato de datos JSON
(JavaScript Object Notation), permitiendo la serialización y deserialización
de datos en formato JSON.
• re: Ofrece funciones y clases para trabajar con expresiones regulares, lo
que permite buscar y manipular patrones en cadenas de texto.
Estas son solo algunas de las bibliotecas de módulos estándar más utilizadas en
Python. Sin embargo, Python ofrece muchas más bibliotecas útiles para
diferentes propósitos, como manejo de archivos, networking, procesamiento de
datos, interfaces gráficas, entre otros.

5. DIR
La función dir() es una función integrada de Python que se utiliza para obtener
una lista de nombres definidos actualmente en un módulo, un objeto o en el
ámbito actual. Proporciona una forma conveniente de explorar y obtener
información sobre los atributos y métodos disponibles en un objeto o módulo.

4
La sintaxis básica de la función dir() es la siguiente:
dir([objeto])

Donde [objeto] es un argumento opcional que representa el objeto del cual


deseas obtener la lista de nombres. Si no se proporciona ningún objeto, dir() se
aplicará al ámbito actual.
A continuación, se muestran algunos ejemplos de cómo usar la función dir():
Usar dir() en el ámbito global para obtener una lista de nombres definidos
actualmente:
print(dir())
SALIDA : ['__builtins__', '__doc__', '__loader__',
'__name__', '__package__', '__spec__', 'x', 'y', 'z']

Usar dir() en un módulo para obtener una lista de nombres definidos en ese
módulo:
import math
print(dir(math))
SALIDA: ['__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan',
'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh',
'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1',
'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum',
'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite',
'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10',
'log1p', 'log2', 'modf', 'nan', 'perm', 'pi', 'pow', 'prod',
'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan',
'tanh', 'tau', 'trunc']

Usar dir() en un objeto para obtener una lista de atributos y métodos disponibles
para ese objeto:
lista = [1, 2, 3]
print(dir(lista))
SALIDA: ['__add__', '__class__', '__contains__',
'__delattr__', '__delitem__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__',
'__init__', '__init_subclass__', '__iter__', '__le__',
'__len__', '__lt__', '__mul__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__reversed__',
'__rmul__', '__setattr__', '__setitem__', '__sizeof__',
'__str__', '__subclasshook__', 'append', 'clear', 'copy',
'count', 'extend', 'index', 'insert', 'pop', 'remove',
'reverse', 'sort']
5
Al ejecutar estos ejemplos, obtendrás una lista de nombres disponibles en el
ámbito actual, en el módulo math y en el objeto lista, respectivamente. La lista
resultante incluirá nombres de variables, funciones, clases y otros atributos
definidos.

Es importante tener en cuenta que la función dir() solo muestra los nombres
definidos en un objeto, pero no proporciona detalles sobre su funcionalidad. Para
obtener información adicional sobre un nombre en particular, puedes consultar
la documentación o utilizar otras funciones de exploración, como help().

6. PAQUETES
En Python, un paquete es una forma de organizar y estructurar módulos
relacionados. Un paquete es simplemente una carpeta (directorio) que contiene
uno o más archivos de módulo de Python, junto con un archivo especial llamado
__init__.py. El archivo __init__.py puede estar vacío o puede contener código
que se ejecuta cuando el paquete se importa.
Los paquetes en Python brindan una manera conveniente de agrupar módulos
relacionados, lo que facilita su organización y reutilización en diferentes
proyectos. Algunas ventajas de usar paquetes son:
• Organización lógica: Los paquetes permiten agrupar módulos
relacionados en una estructura jerárquica, lo que facilita la navegación y
comprensión de un conjunto de módulos.
• Evitar conflictos de nombres: Al agrupar los módulos en paquetes, se
pueden evitar colisiones de nombres, ya que cada módulo se importa
utilizando su nombre completo que incluye el nombre del paquete.
• Facilidad de reutilización: Los paquetes proporcionan una forma de
empaquetar y distribuir código para su reutilización en diferentes
proyectos. Los paquetes pueden instalarse y utilizarse en múltiples
proyectos sin tener que copiar y pegar el código.

Para crear un paquete en Python, debes seguir estos pasos:

Crear una carpeta (directorio) para el paquete. El nombre de la carpeta será el


nombre del paquete.
Agregar un archivo __init__.py dentro de la carpeta. Este archivo puede estar
vacío o contener código de inicialización del paquete.
Agregar los módulos relacionados al paquete. Cada módulo es un archivo .py
dentro de la carpeta.

6
mi_paquete/
__init__.py
modulo1.py
modulo2.py

Una vez que hayas creado el paquete, puedes utilizarlo en tus programas
importando los módulos que necesitas utilizando la sintaxis import:
import mi_paquete.modulo1
from mi_paquete import modulo2

mi_paquete.modulo1.funcion1()
modulo2.funcion2()

Ejemplo:
Supongamos que tienes un proyecto relacionado con geometría que requiere
cálculos de áreas y perímetros de diferentes figuras. Puedes crear un paquete
llamado geometria que contenga módulos para diferentes tipos de figuras
geométricas. Veamos cómo se puede estructurar:
geometria/
__init__.py
formas/
__init__.py
cuadrado.py
circulo.py
triangulo.py
calculadora.py

En este ejemplo, el paquete geometria contiene una carpeta llamada formas, que
a su vez contiene los módulos cuadrado.py, circulo.py y triangulo.py. Además,
tenemos el módulo calculadora.py que se encuentra en el nivel superior del
paquete.
El archivo __init__.py en la carpeta geometria y en la subcarpeta formas indica
que es un paquete y puede estar vacío o contener código de inicialización.
Vamos a ver cómo se podrían implementar algunos de los módulos:

cuadrado.py

7
def calcular_area(lado):
return lado ** 2

def calcular_perimetro(lado):
return 4 * lado
circulo.py
import math

def calcular_area(radio):
return math.pi * radio ** 2

def calcular_perimetro(radio):
return 2 * math.pi * radio
calculadora.py
from geometria.formas.cuadrado import calcular_area as
area_cuadrado
from geometria.formas.cuadrado import calcular_perimetro as
perimetro_cuadrado
from geometria.formas.circulo import calcular_area as
area_circulo
from geometria.formas.circulo import calcular_perimetro as
perimetro_circulo

lado = 4
radio = 2

area = area_cuadrado(lado)
perimetro = perimetro_cuadrado(lado)
print(f"Cuadrado - Área: {area}, Perímetro: {perimetro}")

area = area_circulo(radio)

8
perimetro = perimetro_circulo(radio)
print(f"Círculo - Área: {area}, Perímetro: {perimetro}")

En el archivo calculadora.py, importamos las funciones calcular_area y


calcular_perimetro de los módulos cuadrado y circulo utilizando la sintaxis from
modulo import funcion. Luego, realizamos cálculos de área y perímetro para un
cuadrado y un círculo.
Al ejecutar el archivo calculadora.py, obtendrás la salida:
Cuadrado - Área: 16, Perímetro: 16
Círculo - Área: 12.566370614359172, Perímetro:
12.566370614359172

9
1. OBJETOS
En la programación orientada a objetos (POO), un objeto es una entidad que
combina datos (llamados atributos) y comportamiento (llamado métodos)
relacionados en una sola unidad. Los objetos son instancias de una clase, que
es una plantilla o molde que define la estructura y el comportamiento de los
objetos de ese tipo en particular.
Las ventajas de la programación orientada a objetos son las siguientes:
• Reutilización de código: La POO fomenta la reutilización de código a
través de la creación de clases y la creación de múltiples objetos a partir
de esas clases. Esto permite aprovechar y mantener el código existente
en lugar de tener que volver a escribirlo desde cero.
• Modularidad: La POO facilita la creación de programas modulares. Los
objetos encapsulan datos y comportamiento relacionados, lo que permite
dividir un programa en componentes más pequeños y manejables. Cada
objeto puede ser desarrollado y probado de manera independiente, lo que
mejora la legibilidad y mantenibilidad del código.
• Abstracción: La POO permite la creación de abstracciones que
representan conceptos del mundo real. Puedes modelar objetos del
mundo real como objetos en tu programa, lo que facilita el diseño y la
comprensión del software. Por ejemplo, puedes crear una clase "Coche"
que tenga atributos como "color" y "velocidad" y métodos como "acelerar"
y "frenar", lo que refleja la realidad de un coche.
• Encapsulación: La encapsulación es un principio importante en la POO.
Permite ocultar los detalles internos de un objeto y exponer solo una
interfaz bien definida para interactuar con él. Esto proporciona una mayor
seguridad y evita que se acceda o se modifique directamente los datos
internos del objeto.
• Herencia: La herencia es un concepto clave en la POO que permite crear
nuevas clases basadas en clases existentes. Una clase derivada (o
subclase) hereda los atributos y métodos de la clase base (o superclase).
Esto permite extender y especializar el comportamiento de una clase sin
tener que volver a escribir código, lo que facilita la organización jerárquica
y la reutilización.
En contraste, la programación estructurada se basa en el concepto de
procedimientos o funciones, donde se divide el programa en funciones
independientes que manipulan datos estructurados. La programación
estructurada se enfoca en la lógica y los algoritmos, mientras que la POO se
enfoca en el modelado de entidades y su interacción.
2. TYPE
Si recordamos de las unidades anteriores, Python nos proveía de la la función
type() que se puede utilizar para verificar los tipos de entidades, como números,
cadenas de texto, listas, diccionarios, entre otros.
# Verificar el tipo de un número
1
numero = 10
print(type(numero)) # Imprimirá "<class 'int'>"

# Verificar el tipo de una cadena de texto


texto = "Hola, mundo"
print(type(texto)) # Imprimirá "<class 'str'>"

# Verificar el tipo de una lista


lista = [1, 2, 3, 4, 5]
print(type(lista)) # Imprimirá "<class 'list'>"

# Verificar el tipo de un diccionario


diccionario = {"clave": "valor"}
print(type(diccionario)) # Imprimirá "<class 'dict'>"

Como se puede ver, type nos esta devolviendo ocmo información class, lo que
indica que la entidad que estamos consultando es un objeto!

3. OBJETOS EN PYTHON
En Python, un objeto es una entidad que combina datos y funciones relacionadas
en una sola unidad. Los objetos son instancias de una clase, que es una plantilla
que define la estructura y el comportamiento de los objetos de ese tipo en
particular.
En este ejemplo, se define una clase llamada Persona. La clase tiene un
constructor __init__() que se ejecuta cuando se crea una nueva instancia de la
clase. El constructor toma dos parámetros: nombre y edad. Estos parámetros se
asignan a los atributos nombre y edad del objeto utilizando la sintaxis self.nombre
y self.edad.
La clase Persona también tiene un método llamado saludar(), que imprime un
mensaje de saludo con el nombre y la edad de la persona.
Luego, se crea una instancia de la clase Persona llamada persona1, pasando
los valores "Juan" y 30 como argumentos al constructor. Para acceder a los
atributos del objeto persona1, se utiliza la sintaxis objeto.atributo (por ejemplo,
persona1.nombre).

2
Finalmente, se llama al método saludar() del objeto persona1, utilizando la
sintaxis objeto.metodo() (por ejemplo, persona1.saludar()). Esto imprimirá el
mensaje "Hola, mi nombre es Juan y tengo 30 años."

# Definir una clase llamada Persona


class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad

def saludar(self):
print(f"Hola, mi nombre es {self.nombre} y tengo
{self.edad} años.")

# Crear una instancia de la clase Persona


persona1 = Persona("Juan", 30)

# Acceder a los atributos del objeto persona1


print(persona1.nombre) # Imprimirá "Juan"
print(persona1.edad) # Imprimirá 30

# Llamar al método saludar() del objeto persona1


persona1.saludar() # Imprimirá "Hola, mi nombre es Juan y
tengo 30 años."

3.1. CONSTRUCTOR
Un constructor en programación orientada a objetos es un método especial que
se utiliza para inicializar un objeto cuando se crea una instancia de una clase. El
constructor se llama automáticamente al crear un nuevo objeto y se encarga de
establecer los valores iniciales de los atributos del objeto.
En Python, el constructor se define mediante un método llamado __init__(). El
nombre __init__ es reservado y no debe ser cambiado. Este método puede tener
parámetros para recibir valores que se utilizarán para inicializar los atributos del
objeto.

3
Ejemplo 1: Constructor sin parámetros:
class Persona:
def __init__(self):
self.nombre = "Juan"
self.edad = 30

# Crear una instancia de la clase Persona


persona1 = Persona()

# Acceder a los atributos del objeto persona1


print(persona1.nombre) # Imprimirá "Juan"
print(persona1.edad) # Imprimirá 30

En este ejemplo, se define una clase Persona con un constructor __init__() que
no recibe ningún parámetro. Dentro del constructor, se inicializan los atributos
nombre y edad con valores predeterminados. Al crear una instancia de la clase
Persona utilizando persona1 = Persona(), se llama automáticamente al
constructor y se crean los atributos nombre y edad en el objeto persona1.
Ejemplo 2: Constructor con parámetros:
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad

# Crear una instancia de la clase Persona con valores


personalizados
persona2 = Persona("María", 25)

# Acceder a los atributos del objeto persona2


print(persona2.nombre) # Imprimirá "María"
print(persona2.edad) # Imprimirá 25
En este ejemplo, se define una clase Persona con un constructor __init__() que
recibe dos parámetros: nombre y edad. Los parámetros se utilizan para inicializar
los atributos nombre y edad del objeto. Al crear una instancia de la clase Persona
utilizando persona2 = Persona("María", 25), se pasa los valores "María" y 25 al
4
constructor, que se utilizan para inicializar los atributos correspondientes en el
objeto persona2.
El constructor es opcional en una clase. Si no se define un constructor, Python
proporcionará uno por defecto que no realiza ninguna acción específica.
3.2. ATRIBUTOS
En Python, un atributo de clase es una variable que pertenece a la clase en sí,
en lugar de pertenecer a una instancia particular de la clase. Esto significa que
todos los objetos creados a partir de la clase comparten el mismo valor para el
atributo de clase.

Para definir un atributo de clase en Python, se coloca la variable dentro de la


definición de la clase, pero fuera de cualquier método. Se accede a los atributos
de clase utilizando el nombre de la clase o cualquier objeto creado a partir de
esa clase.
Ejemplo 1: Atributo de clase básico:
class Circulo:
# Atributo de clase
pi = 3.14159

# Acceder al atributo de clase


print(Circulo.pi) # Imprimirá 3.14159

# Crear objetos de la clase Circulo


circulo1 = Circulo()
circulo2 = Circulo()

# Acceder al atributo de clase a través de los objetos


print(circulo1.pi) # Imprimirá 3.14159
print(circulo2.pi) # Imprimirá 3.14159

En este ejemplo, se define la clase Circulo con un atributo de clase llamado pi.
El atributo pi se define fuera de cualquier método y se accede utilizando el
nombre de la clase Circulo o cualquier objeto creado a partir de ella. Todos los
objetos de la clase Circulo comparten el mismo valor para el atributo pi, que es
3.14159.

5
Ejemplo 2: Atributo de clase modificado por una instancia:

class CuentaBancaria:
tasa_interes = 0.05

# Acceder al atributo de clase


print(CuentaBancaria.tasa_interes) # Imprimirá 0.05

# Modificar el atributo de clase a través de una instancia


cuenta1 = CuentaBancaria()
cuenta1.tasa_interes = 0.07

# Acceder al atributo de clase a través de la instancia y la


clase
print(cuenta1.tasa_interes) # Imprimirá 0.07
print(CuentaBancaria.tasa_interes) # Imprimirá 0.05

En este ejemplo, se define la clase CuentaBancaria con un atributo de clase


llamado tasa_interes. El atributo tasa_interes tiene un valor predeterminado de
0.05. Sin embargo, también se puede acceder y modificar a través de una
instancia de la clase. Cuando se modifica el atributo de clase a través de la
instancia (cuenta1.tasa_interes = 0.07), se crea un nuevo atributo específico
para esa instancia, que tiene prioridad sobre el atributo de clase. Los demás
objetos y la clase en sí mantendrán el valor original del atributo de clase.
3.3. METODOS
En Python, un método es una función que está asociada a una clase y se utiliza
para definir el comportamiento de los objetos de esa clase. Los métodos son
similares a las funciones, pero se definen dentro de la definición de la clase y
pueden acceder y manipular los atributos del objeto.
Existen también los métodos especiales, también conocidos como métodos
mágicos o dunder methods (por su nombre en inglés, "double underscore").
Estos métodos tienen nombres especiales que comienzan y terminan con doble
guion bajo (__). Proporcionan una forma de implementar comportamientos
específicos en una clase y son llamados automáticamente en ciertas situaciones.
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
6
self.edad = edad

def saludar(self):
print(f"Hola, mi nombre es {self.nombre} y tengo
{self.edad} años.")

def cumpleanios(self):
self.edad += 1
print(f"Feliz cumpleaños, ahora tengo {self.edad}
años.")

# Crear una instancia de la clase Persona


persona1 = Persona("Juan", 30)

# Llamar al método saludar()


persona1.saludar() # Imprimirá "Hola, mi nombre es Juan y
tengo 30 años."

# Llamar al método cumpleanios()


persona1.cumpleanios() # Imprimirá "Feliz cumpleaños, ahora
tengo 31 años."

En este ejemplo, se define la clase Persona con tres métodos: __init__(),


saludar(), y cumpleanios(). El método __init__() es el constructor y se llama
automáticamente al crear una instancia de la clase. Los métodos saludar() y
cumpleanios() son definidos por el usuario.
El método saludar() imprime un mensaje de saludo utilizando los atributos
nombre y edad del objeto. El método cumpleanios() incrementa la edad en 1 y
luego imprime un mensaje de felicitación.
Para llamar a un método, se utiliza la sintaxis objeto.metodo(). En el ejemplo, se
crea una instancia de la clase Persona llamada persona1. Luego, se llama a los
métodos saludar() y cumpleanios() utilizando persona1.saludar() y
persona1.cumpleanios() respectivamente.
Los métodos especiales se utilizan para proporcionar comportamientos
específicos, como la representación de un objeto como una cadena de texto, la
sobrecarga de operadores, el manejo de iteraciones, entre otros. Algunos

7
ejemplos de métodos especiales en Python son __str__(), __len__(), __add__(),
__iter__(), entre otros.
Por ejemplo, aquí tienes un método especial __str__() que permite representar
un objeto Persona como una cadena de texto:
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad

def __str__(self):
return f"Persona(nombre={self.nombre},
edad={self.edad})"

# Crear una instancia de la clase Persona


persona1 = Persona("Juan", 30)

# Utilizar el método especial __str__()


print(persona1) # Imprimirá "Persona(nombre=Juan, edad=30)"

En este caso, el método __str__() se define para devolver una representación en


forma de cadena de texto del objeto Persona. Al utilizar print(persona1), se llama
automáticamente al método __str__() y se imprime la representación
personalizada del objeto.
3.4. COMPARACION DE OBJETOS
En Python, la comparación de objetos se realiza utilizando los operadores de
comparación, como el operador de igualdad (==), el operador de desigualdad
(!=), los operadores de comparación mayor que (>), menor que (<), mayor o igual
que (>=) y menor o igual que (<=).
Cuando se comparan objetos utilizando los operadores de comparación, se
compara la identidad de los objetos por defecto. Es decir, se verifica si los objetos
son el mismo objeto en memoria, no si tienen los mismos valores o atributos.
Sin embargo, es posible personalizar la comparación de objetos definiendo los
métodos especiales __eq__(), __ne__(), __gt__(), __lt__(), __ge__(), y __le__().
Estos métodos permiten especificar cómo se debe realizar la comparación entre
objetos de una clase.

class Persona:
8
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad

def __eq__(self, otro):


if isinstance(otro, Persona):
return self.nombre == otro.nombre and self.edad
== otro.edad
return False

# Crear instancias de la clase Persona


persona1 = Persona("Juan", 30)
persona2 = Persona("Juan", 30)
persona3 = Persona("María", 25)

# Comparar objetos utilizando el operador de igualdad (==)


print(persona1 == persona2) # Imprimirá True
print(persona1 == persona3) # Imprimirá False

En este ejemplo, se define la clase Persona con un método especial __eq__()


para personalizar la comparación de igualdad entre objetos. El método __eq__()
verifica si el objeto pasado como argumento (otro) es una instancia de la clase
Persona y luego compara los atributos nombre y edad de los objetos para
determinar si son iguales.
Al utilizar el operador de igualdad (==) para comparar persona1 y persona2, se
llamará al método __eq__() definido en la clase Persona. Como los objetos
tienen el mismo nombre y edad, la comparación devolverá True. Sin embargo, al
comparar persona1 y persona3, que tienen diferentes nombres, la comparación
devolverá False.
Es importante tener en cuenta que la implementación de la comparación de
objetos depende de las necesidades específicas de tu programa y de la lógica
que deseas aplicar en la comparación. Los métodos especiales __eq__(),
__ne__(), __gt__(), __lt__(), __ge__(), y __le__() te permiten personalizar estas
comparaciones según tus requerimientos.

4. PENSAR EN OBJETOS

9
Cuando se aborda un problema utilizando programación orientada a objetos, se
enfatiza en identificar los objetos relevantes en el dominio del problema y cómo
interactúan entre sí.
• Identificar los objetos: Analiza el problema y determina qué elementos o
entidades están involucrados. Los objetos son representaciones de estas
entidades en el mundo real o abstracto. Por ejemplo, si estamos
resolviendo un problema de una tienda en línea, algunos objetos
potenciales podrían ser "cliente", "producto", "carrito de compras", etc.
• Definir las propiedades y comportamientos de los objetos: Para cada
objeto identificado, piensa en las características que lo describen
(propiedades) y las acciones que puede realizar (comportamientos o
métodos). Por ejemplo, un objeto "producto" podría tener propiedades
como "nombre", "precio" y "cantidad en stock", y comportamientos como
"calcular_descuento" o "actualizar_stock".
• Identificar las interacciones entre objetos: Determina cómo los objetos
interactúan entre sí para resolver el problema. ¿Cómo se comunican los
objetos y cómo se influyen mutuamente? Estas interacciones pueden ser
en forma de mensajes enviados entre objetos para solicitar información o
realizar acciones.
• Modelar las relaciones entre objetos: Define las relaciones entre los
objetos, como la asociación, la composición o la herencia. Estas
relaciones ayudan a estructurar y organizar el código de manera más
coherente. Por ejemplo, en una tienda en línea, puede haber una relación
de asociación entre los objetos "cliente" y "carrito de compras", ya que un
cliente puede tener un carrito de compras asociado.
• Implementar las clases y objetos en el código: Con base en la estructura
conceptual desarrollada, implementa las clases y crea instancias de los
objetos en el código. Cada clase representa un tipo de objeto y define sus
propiedades y comportamientos. Las instancias de objetos son los datos
reales que se crean a partir de esas clases.
• Utilizar los objetos para resolver el problema: Utiliza los objetos creados
para realizar las operaciones necesarias y resolver el problema. Llama a
los métodos de los objetos, pasa mensajes entre ellos y utiliza sus
propiedades para llevar a cabo las acciones requeridas.
Al pensar en la solución como objetos, se fomenta el enfoque en la estructura y
el diseño del código, lo que permite una mayor modularidad, reutilización y
mantenibilidad. Además, la programación orientada a objetos proporciona
abstracciones más cercanas a la forma en que pensamos y nos relacionamos
con los conceptos en el mundo real, lo que puede hacer que el código sea más
comprensible y escalable.
Es importante tener en cuenta que el proceso de pensar en la solución como
objetos puede variar según el problema y la complejidad del mismo. La práctica

10
y la experiencia en el desarrollo orientado a objetos ayudarán a perfeccionar esta
habilidad y a tomar decisiones más efectivas en el diseño de las clases y objetos.
Ejemplo:
Problema: Crear un sistema de gestión de una biblioteca.
Pasos del proceso:
1. Identificar los objetos: En este caso, algunos objetos relevantes podrían ser
"Biblioteca", "Libro" y "Usuario".

2. Definir las propiedades y comportamientos de los objetos:


El objeto "Biblioteca" podría tener propiedades como "nombre" y "ubicación", y
comportamientos como "agregar_libro", "prestar_libro" y "buscar_libro".
El objeto "Libro" podría tener propiedades como "título", "autor" y "disponible", y
comportamientos como "obtener_info" y "cambiar_estado_disponibilidad".
El objeto "Usuario" podría tener propiedades como "nombre", "ID" y
"libros_prestados", y comportamientos como "registrar_prestamo" y
"devolver_libro".
3. Identificar las interacciones entre objetos:
Un usuario puede solicitar un préstamo de un libro a la biblioteca.
La biblioteca verifica la disponibilidad del libro y registra el préstamo.
El libro actualiza su estado de disponibilidad y se agrega a la lista de libros
prestados del usuario.
4. Modelar las relaciones entre objetos:
La biblioteca puede tener una asociación con los objetos "Libro" y "Usuario".
El objeto "Usuario" podría tener una composición con el objeto "Libro", ya que
puede poseer varios libros.
5. Implementar las clases y objetos en el código:
class Biblioteca:
def __init__(self, nombre, ubicacion):
self.nombre = nombre
self.ubicacion = ubicacion
self.libros = []

def agregar_libro(self, libro):


self.libros.append(libro)

11
def prestar_libro(self, libro, usuario):
if libro.disponible:
libro.cambiar_estado_disponibilidad(False)
usuario.registrar_prestamo(libro)
print(f"El libro '{libro.titulo}' ha sido
prestado a {usuario.nombre}.")
else:
print(f"El libro '{libro.titulo}' no está
disponible en este momento.")

def buscar_libro(self, titulo):


for libro in self.libros:
if libro.titulo == titulo:
return libro
return None

class Libro:
def __init__(self, titulo, autor):
self.titulo = titulo
self.autor = autor
self.disponible = True

def obtener_info(self):
print(f"Título: {self.titulo}")
print(f"Autor: {self.autor}")
print(f"Disponible: {'Sí' if self.disponible else
'No'}")

def cambiar_estado_disponibilidad(self, disponible):


self.disponible = disponible

12
class Usuario:
def __init__(self, nombre, ID):
self.nombre = nombre
self.ID = ID
self.libros_prestados = []

def registrar_prestamo(self, libro):


self.libros_prestados.append(libro)

def devolver_libro(self, libro):


if libro in self.libros_prestados:
libro.cambiar_estado_disponibilidad(True)
self.libros_prestados.remove(libro)
print(f"El libro '{libro.titulo}' ha sido
devuelto.")
else:
print(f"No tienes el libro '{libro.titulo}'
prestado.")

# Crear instancias de objetos


biblioteca = Biblioteca("Biblioteca Central", "Ciudad A")
libro1 = Libro("El Gran Gatsby", "F. Scott Fitzgerald")
libro2 = Libro("1984", "George Orwell")
usuario1 = Usuario("Juan", 123456)

# Agregar libros a la biblioteca


biblioteca.agregar_libro(libro1)
biblioteca.agregar_libro(libro2)

13
# Prestar un libro a un usuario
biblioteca.prestar_libro(libro1, usuario1)

# Mostrar información del libro


libro1.obtener_info()

# Devolver un libro
usuario1.devolver_libro(libro1)

En este ejemplo, se definen las clases Biblioteca, Libro y Usuario con sus
respectivas propiedades y comportamientos. Luego, se crean instancias de los
objetos y se utilizan los métodos para agregar libros a la biblioteca, prestar un
libro a un usuario, obtener información del libro y devolver un libro prestado.
Este enfoque de programación orientada a objetos ayuda a organizar la lógica
del programa de manera más modular y facilita la representación de las
entidades del mundo real (en este caso, una biblioteca, libros y usuarios).

14
1. HERENCIA
La herencia es un concepto fundamental en la programación orientada a objetos
que permite la creación de nuevas clases basadas en clases existentes. En
términos sencillos, la herencia implica la capacidad de una clase (llamada clase
derivada o subclase) de heredar los atributos y métodos de otra clase (llamada
clase base o superclase).
Las ventajas de utilizar la herencia en la programación orientada a objetos son:
• Reutilización de código: La herencia permite aprovechar el código
existente de la clase base en la clase derivada. Los atributos y métodos
definidos en la clase base pueden ser utilizados directamente en la clase
derivada sin necesidad de volver a escribirlos.
• Modularidad y extensibilidad: La herencia permite crear una jerarquía
de clases, donde cada clase derivada puede agregar o modificar el
comportamiento de la clase base. Esto facilita la organización y
estructuración del código, así como la incorporación de nuevas
funcionalidades en las clases derivadas.
• Polimorfismo: La herencia permite el uso del polimorfismo, lo que
significa que los objetos de las clases derivadas pueden ser tratados como
objetos de la clase base. Esto brinda flexibilidad en la programación, ya
que se puede escribir código genérico que funcione con diferentes tipos
de objetos.
class Vehiculo:
def __init__(self, marca, modelo):
self.marca = marca
self.modelo = modelo

def conducir(self):
print("El vehículo está en movimiento.")

class Coche(Vehiculo):
def __init__(self, marca, modelo, color):
super().__init__(marca, modelo)
self.color = color

def conducir(self):
print(f"El coche {self.marca} {self.modelo} de color
{self.color} está en movimiento.")

1
class Moto(Vehiculo):
def conducir(self):
print("La moto está en movimiento.")

# Crear objetos de las clases derivadas


coche = Coche("Ford", "Mustang", "rojo")
moto = Moto("Honda", "CBR")

# Llamar a los métodos de las clases derivadas


coche.conducir() # Salida: El coche Ford Mustang de color
rojo está en movimiento.
moto.conducir() # Salida: La moto está en movimiento.

En este ejemplo, la clase Vehiculo es la clase base que define un vehículo


genérico con un método conducir(). La clase Coche y la clase Moto son clases
derivadas que heredan de la clase Vehiculo. La clase Coche sobrescribe el
método conducir() para imprimir información específica del coche, mientras que
la clase Moto utiliza la implementación heredada del método conducir().
La herencia permite que las clases derivadas (Coche y Moto) compartan
características y comportamiento comunes con la clase base (Vehiculo) y, al
mismo tiempo, extiendan o modifiquen estos atributos y métodos según sea
necesario. Esto promueve la reutilización del código y facilita la creación de una
jerarquía de clases coherente y organizada.
2. POLIMORFISMO
El polimorfismo es otro concepto base en la programación orientada a objetos
que se refiere a la capacidad de un objeto de tomar diferentes formas o
comportarse de diferentes maneras. En términos más generales, el polimorfismo
permite que objetos de diferentes clases sean tratados de manera uniforme a
través de una interfaz común.
El polimorfismo es conveniente de usar cuando se tiene un conjunto de clases
relacionadas que comparten una interfaz común, pero implementan
comportamientos específicos de manera diferente. Proporciona flexibilidad y
extensibilidad al código, ya que permite que se utilice un único método o función
para trabajar con diferentes tipos de objetos, sin necesidad de conocer el tipo
específico en tiempo de compilación.
En Python, el polimorfismo se logra mediante la implementación de métodos con
el mismo nombre en diferentes clases. Estos métodos deben tener la misma
firma (es decir, el mismo nombre y la misma lista de parámetros), pero pueden
2
tener implementaciones diferentes. Al llamar al método a través de una
referencia de tipo genérico, el comportamiento adecuado se determina en tiempo
de ejecución según el tipo real del objeto.
class Animal:
def hablar(self):
pass
class Perro(Animal):
def hablar(self):
return "Woof!"
class Gato(Animal):
def hablar(self):
return "¡Miau!"
def hacer_hablar(animal):
print(animal.hablar())

# Crear instancias de diferentes clases


perro = Perro()
gato = Gato()

# Llamar al método hacer_hablar con diferentes objetos


hacer_hablar(perro) # Salida: Woof!
hacer_hablar(gato) # Salida: ¡Miau!

En este ejemplo, las clases Perro y Gato heredan de la clase base Animal y
sobrescriben el método hablar(). La función hacer_hablar() acepta un objeto de
tipo Animal y llama al método hablar() del objeto. Aunque el método hablar() se
llama de la misma manera en ambas clases, cada clase implementa su propio
comportamiento específico. El polimorfismo permite tratar a los objetos Perro y
Gato de manera uniforme a través de la interfaz común proporcionada por la
clase base Animal.
El polimorfismo es una característica poderosa que promueve la reutilización del
código y la flexibilidad en el diseño de sistemas orientados a objetos. Permite
escribir un código más genérico y extensible, ya que se puede agregar nuevas
clases que cumplan con la interfaz común sin necesidad de modificar el código
existente.

3
3. COMPOSICION
La composición de objetos es un concepto en la programación orientada a
objetos que implica combinar objetos más pequeños para construir objetos más
complejos. En lugar de heredar comportamiento de otras clases, la composición
se basa en la creación de relaciones entre objetos a través de la inclusión de una
instancia de una clase dentro de otra.
En Python, la composición se puede lograr mediante la creación de atributos en
una clase que sean instancias de otras clases. Los objetos de la clase
contenedora pueden acceder y utilizar los atributos y métodos de la clase
contenida para lograr cierto comportamiento.
class Motor:
def encender(self):
print("El motor se ha encendido.")

def apagar(self):
print("El motor se ha apagado.")

class Coche:
def __init__(self):
self.motor = Motor() # Instancia de la clase Motor

def encender_coche(self):
self.motor.encender()

def apagar_coche(self):
self.motor.apagar()

coche = Coche()
coche.encender_coche() # Salida: El motor se ha encendido.
coche.apagar_coche() # Salida: El motor se ha apagado.

En este ejemplo, la clase Coche tiene un atributo motor que es una instancia de
la clase Motor. La clase Coche utiliza los métodos encender() y apagar() del
objeto motor para encender y apagar el coche.

4
La composición permite construir objetos complejos al combinar objetos más
pequeños y reutilizar su funcionalidad. En el ejemplo anterior, el coche se
compone de un motor y utiliza sus métodos para lograr ciertos comportamientos.
La relación entre el coche y el motor no es de herencia, sino de composición, lo
que significa que el coche tiene un motor en lugar de ser un tipo de motor.
La composición ofrece ventajas como la modularidad, el bajo acoplamiento y la
facilidad de mantenimiento. Permite crear objetos más complejos al combinar
objetos más simples y mantener una estructura clara y organizada en el código.

4. DELEGACIÓN
La delegación es un concepto en la programación orientada a objetos que se
refiere a la transferencia de responsabilidades de una clase a otra. En lugar de
heredar directamente el comportamiento de una clase, una clase delega la
ejecución de ciertas tareas a otra clase asociada.
En Python, la delegación se puede lograr utilizando la composición, donde una
clase incluye una instancia de otra clase y utiliza sus métodos para realizar
ciertas operaciones. La clase que delega la responsabilidad se conoce como la
clase delegadora y la clase que realiza la tarea delegada se conoce como la
clase delegada.
class Motor:
def encender(self):
print("El motor se ha encendido.")

def apagar(self):
print("El motor se ha apagado.")

class Coche:
def __init__(self):
self.motor = Motor() # Instancia de la clase Motor

def encender_coche(self):
self.motor.encender()

def apagar_coche(self):
self.motor.apagar()

5
coche = Coche()
coche.encender_coche() # Salida: El motor se ha encendido.
coche.apagar_coche() # Salida: El motor se ha apagado.

En este ejemplo, la clase Coche tiene una instancia de la clase Motor y utiliza
sus métodos encender() y apagar() para encender y apagar el coche. En lugar
de heredar directamente el comportamiento del motor, la clase Coche delega
estas tareas al objeto motor.
La delegación permite una mayor flexibilidad y modularidad en el diseño de
clases, ya que las responsabilidades se pueden separar y asignar a diferentes
clases según sea necesario. Además, si la implementación del motor cambia en
el futuro, solo se necesita modificar la clase Motor sin afectar a la clase Coche.
5. COMPOSICION VS DELEGACIÓN
La composición y la delegación son dos conceptos relacionados pero distintos
en la programación orientada a objetos:
Composición: La composición implica la relación entre dos objetos donde uno de
ellos contiene al otro como parte integral de su estructura. En la composición, un
objeto se crea utilizando otros objetos como componentes o partes. El objeto
contenedor tiene una referencia a los objetos contenidos y los utiliza para lograr
su funcionalidad. La relación es de "tiene un" o "está compuesto por". La
composición se logra mediante la creación de atributos en una clase que son
instancias de otras clases. Por ejemplo, una clase Coche puede tener un atributo
motor que es una instancia de la clase Motor.
Delegación: La delegación implica la transferencia de responsabilidades de una
clase a otra. En lugar de heredar directamente el comportamiento de una clase,
una clase delega la ejecución de ciertas tareas a otra clase asociada. En la
delegación, un objeto utiliza otro objeto para llevar a cabo una operación
específica en su nombre. La relación es de "utiliza" o "delega a". La delegación
se logra a través de la inclusión de una instancia de una clase dentro de otra
clase. Por ejemplo, una clase Coche puede tener un atributo motor que es una
instancia de la clase Motor, y la clase Coche utiliza los métodos del objeto motor
para encender y apagar el coche.
En resumen, la diferencia principal entre composición y delegación radica en el
propósito de la relación entre objetos. La composición se centra en la creación
de objetos complejos mediante la combinación de objetos más pequeños, donde
el objeto contenedor es responsable de los objetos contenidos. Por otro lado, la
delegación se centra en transferir responsabilidades a otros objetos, donde el
objeto delegador utiliza otro objeto para realizar ciertas tareas en su nombre.
Ambos conceptos ofrecen flexibilidad y reutilización de código, pero se aplican
en contextos diferentes según las necesidades del diseño y la estructura del
programa.

6
1. PRUEBAS UNITARIAS
Una prueba unitaria es una técnica de pruebas de software que se utiliza para
verificar el funcionamiento individual y aislado de una unidad de código,
generalmente una función, método o clase. El objetivo principal de las pruebas
unitarias es asegurarse de que cada unidad de código funcione correctamente
de manera independiente antes de combinarla con otras partes del programa.
Algunas ventajas de realizar pruebas unitarias son:
• Detección temprana de errores: Las pruebas unitarias pueden ayudar a
identificar errores en el código antes de que se integren con otras partes
del programa. Esto permite corregir los errores de manera temprana y
reduce el tiempo y el esfuerzo necesario para depurar el código más
adelante.
• Mejora la calidad del código: Al escribir pruebas unitarias, se requiere
pensar en diferentes casos y situaciones posibles, lo que puede llevar a
un diseño de código más sólido y modular. Además, las pruebas unitarias
actúan como documentación automatizada, lo que facilita la comprensión
y el mantenimiento del código a largo plazo.
• Facilita la refactorización: Las pruebas unitarias proporcionan confianza
al realizar cambios en el código existente. Si las pruebas unitarias pasan
después de la refactorización, tienes una mayor seguridad de que no has
introducido nuevos errores en el proceso.
Existen otros tipos de pruebas, como las pruebas de integración, pruebas de
aceptación y pruebas de rendimiento, entre otras. Cada tipo de prueba tiene un
propósito específico en el ciclo de desarrollo de software y se enfoca en
diferentes aspectos del sistema.

2. TDD
Las pruebas son tan importantes que incluso existe una metodología
denominada TDD, significa "Test-Driven Development" (Desarrollo Dirigido por
Pruebas, en español). Es una práctica de desarrollo de software en la que las
pruebas unitarias se escriben antes de escribir el código de producción.
El enfoque principal del TDD es seguir un ciclo de desarrollo iterativo y repetitivo,
que generalmente se compone de los siguientes pasos:

• Escribir una prueba: Primero, se escribe una prueba unitaria que defina el
comportamiento esperado de una funcionalidad específica. En esta etapa,
la prueba generalmente fallará porque el código de producción aún no se
ha implementado.
• Ejecutar la prueba: A continuación, se ejecuta la prueba recién escrita.
Como se esperaba, la prueba fallará porque el código de producción
necesario no existe o no está implementado correctamente.

1
• Escribir el código de producción: Ahora, se implementa el código de
producción necesario para que la prueba pase correctamente. El objetivo
es escribir la cantidad mínima de código necesaria para que la prueba
pase.
• Ejecutar todas las pruebas: Después de escribir el código de producción,
se ejecutan todas las pruebas, incluida la nueva prueba que se acaba de
agregar. Todas las pruebas deben pasar correctamente en esta etapa.
• Refactorizar el código: Si todas las pruebas pasan, se puede proceder a
mejorar la calidad del código sin cambiar su comportamiento externo. Esta
etapa implica revisar y optimizar el código, asegurándose de que siga
siendo legible, mantenible y eficiente.
• Repetir el ciclo: El ciclo se repite escribiendo una nueva prueba para la
siguiente funcionalidad o escenario y luego repitiendo los pasos
anteriores.
La principal idea detrás del TDD es que las pruebas actúan como
especificaciones para el código. Al escribir las pruebas primero, se establece un
objetivo claro y se asegura de que el código esté diseñado para cumplir con ese
objetivo. Además, el TDD fomenta el diseño modular, la cobertura de pruebas y
la refactorización continua del código.
El TDD puede ayudar a mejorar la calidad del código, acelerar el desarrollo al
reducir la cantidad de errores y proporcionar una mayor confianza en el
funcionamiento del software.
3. PyUNIT
PyUnit, también conocido como unittest, es un módulo de Python que
proporciona un marco de pruebas unitarias. Forma parte de la biblioteca estándar
de Python y se basa en el marco de pruebas unitarias de JUnit, que es utilizado
en el lenguaje de programación Java.
El módulo unittest (pyunit) ofrece una serie de clases y métodos que facilitan la
escritura y ejecución de pruebas unitarias en Python. Algunas características
importantes de unittest incluyen:
• Clases de prueba: unittest proporciona la clase TestCase, que se utiliza
como base para definir las pruebas unitarias. Puedes crear subclases de
TestCase y agregar métodos de prueba a esas subclases.

• Métodos de prueba: Los métodos de prueba son funciones que verifican


el comportamiento de una unidad de código específica. Estos métodos
deben comenzar con el prefijo test_ para que unittest los identifique como
pruebas y los ejecute automáticamente.

2
• Aserciones: unittest ofrece una variedad de métodos de aserción (como
assertEqual, assertTrue, assertFalse, entre otros) que permiten verificar
condiciones y comparar valores esperados con los valores obtenidos
durante la ejecución de una prueba.

• Configuración y limpieza: unittest proporciona métodos especiales para


realizar configuración y limpieza antes y después de la ejecución de cada
prueba. Estos métodos, como setUp() y tearDown(), se utilizan para
preparar el entorno de prueba antes de cada prueba y realizar limpieza
posterior.

• Descubrimiento y ejecución de pruebas: unittest incluye herramientas


para descubrir automáticamente las pruebas en un conjunto de archivos
y directorios, y para ejecutarlas en un orden determinado. Puedes ejecutar
las pruebas a través de la línea de comandos o mediante herramientas de
ejecución específicas.

Ejemplo
import unittest

class MyTestCase(unittest.TestCase):
def test_sum(self):
result = 2 + 2
self.assertEqual(result, 4)

if __name__ == '__main__':
unittest.main()

En este ejemplo, creamos una subclase de unittest.TestCase llamada


MyTestCase y definimos un método de prueba llamado test_sum. Dentro de este
método, realizamos una suma y luego usamos self.assertEqual para verificar si
el resultado es igual a 4.
Luego, ejecutamos las pruebas utilizando unittest.main(), que descubre
automáticamente todas las pruebas en el archivo y las ejecuta.
4. Metodos assert

3
La biblioteca unittest proporciona una variedad de métodos assert que puedes
utilizar para verificar diferentes condiciones en tus pruebas unitarias. Algunos de
los métodos assert más comunes incluyen:

• assertEqual(a, b): Verifica que a sea igual a b.


• assertNotEqual(a, b): Verifica que a no sea igual a b.
• assertTrue(x): Verifica que x sea verdadero.
• assertFalse(x): Verifica que x sea falso.
• assertIs(a, b): Verifica que a sea el mismo objeto que b.
• assertIsNot(a, b): Verifica que a no sea el mismo objeto que b.
• assertIsNone(x): Verifica que x sea None.
• assertIsNotNone(x): Verifica que x no sea None.
• assertIn(a, b): Verifica que a esté presente en b.
• assertNotIn(a, b): Verifica que a no esté presente en b.
• assertIsInstance(a, b): Verifica que a sea una instancia de la clase b.
• assertNotIsInstance(a, b): Verifica que a no sea una instancia de la clase
b.
• assertRaises(exception, callable, *args, **kwargs): Verifica que llamar a
callable con los argumentos dados genere una excepción del tipo
exception.
• assertRaisesRegex(exception, regex, callable, *args, **kwargs): Verifica
que llamar a callable genere una excepción del tipo exception y que el
mensaje de error coincida con el patrón de expresión regular regex.
• assertAlmostEqual(a, b): Verifica que a y b sean casi iguales (útil para
comparar números de punto flotante).
• assertNotAlmostEqual(a, b): Verifica que a y b no sean casi iguales.
Para utilizar los métodos de aserción, simplemente llámalos dentro de los
métodos de prueba de tu clase TestCase. Por ejemplo:
import unittest

class MyTestCase(unittest.TestCase):
def test_sum(self):
result = 2 + 2
self.assertEqual(result, 4)

def test_boolean(self):
value = True
self.assertTrue(value)

4
if __name__ == '__main__':
unittest.main()

En este ejemplo, usamos self.assertEqual en el método test_sum para verificar


si la suma de 2 y 2 es igual a 4. También utilizamos self.assertTrue en el método
test_boolean para verificar si la variable value es verdadera.
Si alguna de las aserciones falla, unittest registrará el resultado como una falla
en la prueba y proporcionará información detallada sobre el error.
Recuerda que puedes combinar múltiples aserciones en una sola prueba para
verificar diferentes condiciones y escenarios.
Ejemplo:
Supongamos que tienes una clase llamada Calculator que contiene un método
is_positive() que devuelve True si un número es positivo y False en caso
contrario. Queremos asegurarnos de que el método is_positive() funcione
correctamente.
import unittest

class Calculator:
def is_positive(self, number):
return number > 0

class CalculatorTestCase(unittest.TestCase):
def test_is_positive(self):
calculator = Calculator()
self.assertTrue(calculator.is_positive(5))
self.assertTrue(calculator.is_positive(10))
self.assertFalse(calculator.is_positive(-5))
self.assertFalse(calculator.is_positive(0))

if __name__ == '__main__':
unittest.main()
En este ejemplo, creamos una clase Calculator que tiene un método is_positive()
que verifica si un número es positivo. En nuestra clase CalculatorTestCase,

5
definimos el método test_is_positive() donde realizamos varias aserciones
utilizando assertTrue y assertFalse.

• self.assertTrue(calculator.is_positive(5)) verifica que el resultado de


calculator.is_positive(5) sea verdadero, es decir, que el número 5 sea
considerado positivo.
• self.assertTrue(calculator.is_positive(10)) verifica que el resultado de
calculator.is_positive(10) sea verdadero, es decir, que el número 10 sea
considerado positivo.
• self.assertFalse(calculator.is_positive(-5)) verifica que el resultado de
calculator.is_positive(-5) sea falso, es decir, que el número -5 no sea
considerado positivo.
• self.assertFalse(calculator.is_positive(0)) verifica que el resultado de
calculator.is_positive(0) sea falso, es decir, que el número 0 no sea
considerado positivo.
Si todas las aserciones se cumplen, las pruebas pasarán exitosamente. En caso
de que alguna aserción falle, unittest mostrará información detallada sobre la
falla y la línea de código asociada.
Recuerda que assertTrue se utiliza para verificar que una condición sea
verdadera, mientras que assertFalse se utiliza para verificar que una condición
sea falsa.
5. setUp
El método setUp() es un método especial que se utiliza en unittest para realizar
configuraciones comunes antes de ejecutar cada prueba en una clase TestCase.
Este método se ejecuta automáticamente antes de cada método de prueba y se
utiliza para preparar el entorno necesario para las pruebas.
La función setUp() se define en una subclase de unittest.TestCase y se puede
utilizar para realizar tareas como:
• Configurar objetos o recursos necesarios para las pruebas.
• Inicializar variables.
• Realizar acciones previas a la ejecución de cada prueba.
import unittest

class MyTestCase(unittest.TestCase):
def setUp(self):
# Configuración común para todas las pruebas
self.my_object = MyObject()

6
def test_something(self):
# Acceso a self.my_object en la prueba
result = self.my_object.do_something()
self.assertEqual(result, expected_result)

def test_another_thing(self):
# Acceso a self.my_object en otra prueba
result = self.my_object.do_another_thing()
self.assertEqual(result, expected_result)

if __name__ == '__main__':
unittest.main()

En este ejemplo, la clase MyTestCase hereda de unittest.TestCase y define el


método setUp(). Dentro de setUp(), se realiza la configuración necesaria, que en
este caso es crear una instancia de MyObject y asignarla a self.my_object.
Luego, en los métodos de prueba, como test_something() y test_another_thing(),
puedes acceder a self.my_object y utilizarlo en las pruebas.
Cada vez que se ejecuta un método de prueba, setUp() se ejecutará primero
para asegurarse de que el entorno esté configurado correctamente antes de
ejecutar la prueba.
Es importante destacar que setUp() se ejecuta antes de cada método de prueba,
por lo que cualquier cambio realizado en la configuración dentro de un método
de prueba no afectará a los demás métodos de prueba.
El uso de setUp() ayuda a evitar la duplicación de código y garantiza una
configuración consistente para todas las pruebas en una clase TestCase.
6. tearDown
El método tearDown() es otro método especial que se utiliza en unittest para
realizar tareas de limpieza después de ejecutar cada prueba en una clase
TestCase. Este método se ejecuta automáticamente después de cada método
de prueba y se utiliza para limpiar cualquier configuración o recursos que se
hayan utilizado durante las pruebas.
La función tearDown() se define en una subclase de unittest.TestCase y se puede
utilizar para realizar tareas como:

• Liberar recursos utilizados durante las pruebas.

7
• Restaurar configuraciones a su estado original.
• Realizar acciones posteriores a la ejecución de cada prueba.
import unittest
class MyTestCase(unittest.TestCase):
def setUp(self):
# Configuración común para todas las pruebas
self.my_object = MyObject()

def tearDown(self):
# Tareas de limpieza después de cada prueba
self.my_object.cleanup()

def test_something(self):
# Acceso a self.my_object en la prueba
result = self.my_object.do_something()
self.assertEqual(result, expected_result)

def test_another_thing(self):
# Acceso a self.my_object en otra prueba
result = self.my_object.do_another_thing()
self.assertEqual(result, expected_result)

if __name__ == '__main__':
unittest.main()
En este ejemplo, la clase MyTestCase define tanto el método setUp() como el
método tearDown(). Dentro de tearDown(), se realizan las tareas de limpieza
necesarias, que en este caso implican llamar al método cleanup() en
self.my_object para liberar cualquier recurso o restaurar cualquier configuración
necesaria.
Cada vez que se ejecuta un método de prueba, tearDown() se ejecutará
automáticamente después de ese método de prueba, incluso si el método de
prueba generó una excepción o un error. Esto garantiza que las tareas de
limpieza se realicen independientemente del resultado de la prueba.

8
Es importante destacar que tearDown() se ejecuta después de cada método de
prueba, por lo que cualquier cambio realizado en la limpieza dentro de un método
de prueba no afectará a los demás métodos de prueba.
El uso de tearDown() es opcional y solo se utiliza cuando necesitas realizar
tareas de limpieza específicas después de cada prueba. Si no necesitas realizar
ninguna tarea de limpieza, no es necesario definir el método tearDown() en tu
clase TestCase.
7. Fixture
Lo que fuimos construyendo hasta el momento, en unittest se denomina fixture.
Podemos decir entonces que es un conjunto de datos, configuraciones o
recursos necesarios para llevar a cabo una o más pruebas. Estos fixtures se
utilizan para preparar el entorno de prueba antes de ejecutar las pruebas y
también para realizar tareas de limpieza después de que las pruebas se hayan
completado.
Los fixtures en unittest se implementan como vimos anteriormente, utilizando los
métodos setUp() y tearDown() en una clase TestCase. El método setUp() se
utiliza para configurar el entorno de prueba antes de que se ejecute cada prueba,
mientras que el método tearDown() se utiliza para limpiar y restablecer el entorno
después de cada prueba.
Ejemplo de un fixture completo
import unittest

class MyTestCase(unittest.TestCase):
def setUp(self):
# Configurar el entorno de prueba
# Crear objetos, abrir conexiones, inicializar
variables, etc.

def tearDown(self):
# Limpiar y restablecer el entorno de prueba
# Cerrar conexiones, liberar recursos, revertir
cambios, etc.

def test_something(self):
# Prueba que utiliza el entorno de prueba configurado
en setUp()

9
# Realizar aserciones y verificar resultados

def test_another_thing(self):
# Otra prueba que también utiliza el entorno de
prueba configurado en setUp()
# Realizar aserciones y verificar resultados

if __name__ == '__main__':
unittest.main()
En este ejemplo, el método setUp() se utiliza para configurar el entorno de
prueba común para todas las pruebas. Esto puede incluir la creación de objetos,
la inicialización de variables, la apertura de conexiones a bases de datos, entre
otros.
El método tearDown() se utiliza para realizar tareas de limpieza y restablecer el
entorno de prueba después de cada prueba. Esto puede incluir cerrar conexiones
a bases de datos, liberar recursos, revertir cambios realizados durante la prueba,
entre otros.
Cada prueba en la clase MyTestCase utilizará el entorno de prueba configurado
en setUp() y se ejecutará de forma aislada, sin afectar a las demás pruebas.
Después de que se haya ejecutado cada prueba, se llamará automáticamente al
método tearDown() para limpiar y restablecer el entorno antes de la siguiente
prueba.
El uso de fixtures en unittest ayuda a garantizar que las pruebas se ejecuten en
un entorno controlado y consistente, permitiendo la reutilización de
configuraciones y la limpieza adecuada después de las pruebas.
8. Ejecución de pruebas
Puedes ejecutar todas tus pruebas en un archivo o módulo utilizando la función
unittest.main() como hicimos hasta el momento, ese tipo de ejecución lo
denominamos básicas, pero hay otros modos de ejecutar la prueba.
Ejecución selectiva: Si deseas ejecutar solo una prueba específica o un conjunto
de pruebas, puedes utilizar la línea de comandos junto con el módulo unittest.
Aquí tienes algunos ejemplos:
python -m unittest nombre_del_modulo

Ejecutar todas las pruebas en una clase TestCase específica:


python -m unittest nombre_del_modulo.NombreDeLaClase
Ejecutar una prueba específica dentro de una clase TestCase:

10
python -m unittest
nombre_del_modulo.NombreDeLaClase.nombre_del_metodo_de_prue
ba

Utiliza estos comandos en tu línea de comandos o terminal, reemplazando


nombre_del_modulo, NombreDeLaClase y nombre_del_metodo_de_prueba con
los nombres reales de tu archivo, clase y método de prueba.
Informes de ejecución: unittest proporciona informes detallados sobre la
ejecución de las pruebas. Dependiendo de la configuración, puedes obtener
informes en forma de texto en la consola, informes en formato XML, HTML, entre
otros.
Para obtener informes en formato XML, puedes usar la opción -xml al ejecutar
las pruebas:
python -m unittest nombre_del_modulo -xml

Esto generará un archivo XML con información detallada sobre la ejecución de


las pruebas.
9. Colección de casos de prueba: TestSuite
En unittest, una test suite (suite de pruebas) es una colección de casos de prueba
que se agrupan lógicamente para ejecutarse juntos. Permite ejecutar conjuntos
específicos de pruebas en lugar de ejecutar todas las pruebas en un archivo o
módulo.
Una test suite se crea utilizando la clase TestSuite de unittest. Puedes agregar
instancias de clases TestCase o incluso otras test suites a la suite de pruebas
utilizando los métodos addTest() o addTests(). Luego, puedes ejecutar la test
suite para ejecutar todas las pruebas que contiene.
import unittest
# Importa las clases de prueba que deseas agregar a la test
suite
from test_module1 import TestClass1
from test_module2 import TestClass2

# Crea una instancia de TestSuite


test_suite = unittest.TestSuite()

# Agrega las clases de prueba a la test suite


test_suite.addTest(unittest.makeSuite(TestClass1))
test_suite.addTest(unittest.makeSuite(TestClass2))

11
# Ejecuta la test suite
unittest.TextTestRunner().run(test_suite)

En este ejemplo, se importan las clases TestClass1 y TestClass2, que contienen


las pruebas que deseas agrupar. Luego, se crea una instancia de TestSuite
llamada test_suite. Luego, se utilizan los métodos addTest() o addTests() para
agregar las clases de prueba a la suite de pruebas.
Finalmente, se utiliza unittest.TextTestRunner().run(test_suite) para ejecutar la
test suite y obtener los resultados de las pruebas en la consola.
Utilizar una test suite es útil cuando deseas ejecutar un conjunto específico de
pruebas en lugar de todas las pruebas en un archivo o módulo. También puedes
anidar test suites dentro de otras test suites para organizar y ejecutar pruebas
en grupos lógicos.
Recuerda que la creación y ejecución de una test suite es opcional. Puedes
ejecutar pruebas individuales o todas las pruebas sin utilizar una test suite. La
test suite proporciona una forma adicional de organizar y ejecutar pruebas según
tus necesidades.

12
1. Bases de datos
¿Qué es una base de datos? También conocidas como bancos de datos, son
simplemente conjuntos de datos. Ya conocen algunos tipos de datos, como los
números, las cadenas de caracteres, las fechas, etc.
Estos conjuntos de datos hacen referencia a información perteneciente a un
mismo contexto. Es decir, si hablamos de los clientes de una empresa, éstos
datos comunes de todos los clientes podrían ser sus nombres, apellidos,
direcciones, teléfonos… O los productos de un negocio, cada uno con su
nombre, precio, descripción, etc.
Por tanto, al ser datos del mismo contexto, las bases de datos permiten
almacenarlos sistemáticamente, de forma automatizada, con la finalidad de un
posterior uso. Ya sea para realizar consultas, comparativas, análisis,
modificaciones o simplemente borrarlos.
Como son programas complejos centrados en la gestión de información, reciben
el nombre de SGBD: Sistemas Gestores de Bases de Datos.
La peculiaridad de los SGBD es que implementan sus propios lenguajes internos
de programación para realizar las consultas, que pueden ser tan simples como
consultar el nombre de todos los clientes de la empresa, o tan complejas como
conseguir información de los pedidos de una tienda, a la vez que se consultan
los clientes y en un conjunto de fechas determinado.
2. Modelos
De todas formas, los tipos de datos y la forma de almacenarlos pueden diferir
mucho dependiendo exactamente del contexto, y es por eso que con el tiempo
se han ido desarrollando una serie de modelos distintos para gestionar las bases
de datos.
Jerárquicas: Utilizan un modelo los datos que se organiza en forma de árbol
invertido, en donde un nodo padre de información puede tener varios hijos...
De red: Una mejora del modelo jerárquico que permite a un hijo tener varios
padres...
Transaccionales: Cuyo único fin es el envío y recepción de datos a grandes
velocidades, estas bases son muy poco comunes
Relacionales: Éste es el modelo utilizado en la actualidad para representar
problemas reales y administrar datos dinámicamente. Es en el que nos vamos a
centrar, pero hay otros...
Documentales: Permiten guardar texto completo, y en líneas generales realizar
búsquedas más potentes. Sirven para almacenar grandes volúmenes de
información de antecedentes históricos. Junto a las relacionales son de las más
utilizadas en el desarrollo web.
Orientadas a objetos: Este modelo es bastante reciente y propio de los
modelos informáticos orientados a objetos, donde se trata de almacenar en la
1
base de datos los objetos completos. Es posible que tome más importancia en
el futuro.
Deductivas: Son bases de datos que permiten hacer deducciones. Se basan
principalmente en reglas y hechos que son almacenados en la base de datos,
por lo que son algo complejas.
3. Modelo Relacional
Las bases de datos Relacionales son muy utilizadas actualmente gracias a que
es fácil representar y gestionar problemas del mundo real.
Se basan en la idea de crear relaciones entre conjuntos de datos, en los que
cada relación es también una tabla. Cada tabla consta de registros, formados
por filas y columnas, también conocidos como tuplas y campos.
Evidentemente dentro de las bases de datos relacionales, existen muchos
SGBD. La mayoría también son compatibles con Python. Algunos son de pago,
otros gratuitos, los hay sencillos y otros muy avanzados. Hagamos un repaso:
SQL Server: Es un sistema de manejo de bases de datos del modelo
relacional, desarrollado por la empresa Microsoft y únicamente disponible para
sistemas Windows. Es privativo y competidor directo de Oracle, MySQL y
PostgreSQL.
Oracle: Database es un sistema de gestión de base de datos de tipo objeto-
relacional privativo, desarrollado por Oracle Corporation, considerado como uno
de los sistemas más completos. Su dominio en el mercado de servidores
empresariales fue casi total hasta la aparición de la competencia. Es
multiplataforma y además las últimas versiones de Oracle han sido certificadas
para poder trabajar bajo GNU/Linux.
MySQL: Es un sistema de gestión de bases de datos relacional desarrollado
bajo licencia dual GPL/Licencia comercial por Oracle Corporation y está
considerada como la base datos open source más popular del mundo, y una de
las más populares en general junto a Oracle y Microsoft SQL Server, sobre todo
para entornos de desarrollo web.
PostgreSQL: Es un Sistema de gestión de bases de datos relacional orientado
a objetos y libre. Como muchos otros proyectos de código abierto, el desarrollo
de PostgreSQL no es manejado por una empresa o persona, sino que es dirigido
por una comunidad de desarrolladores que trabajan de forma desinteresada,
altruista, libre o apoyados por organizaciones comerciales.
SQLite: Es un sistema de gestión de bases de datos relacional contenido en
una pequeña biblioteca escrita en C. Es un proyecto de dominio público y a
diferencia de los otros sistemas que utilizan la arquitectura cliente-servidor, su
motor no es un proceso independiente, sino que se enlaza con el programa
pasando a ser parte integral del mismo. Sin embargo, no os dejéis engañar,
porque, aunque parezca la solución sencilla,

2
SQLite en su tercera versión permite bases de datos de hasta 2 Terabytes de
tamaño y muchas otras funcionalidades.
Así que como ven encontramos multitud de SGBD Relacionales. En Python,
cada uno de ellos cuenta módulos libres y programas conectores para comunicar
las bases de datos y el lenguaje de programación. Sin embargo, pese a que son
sistemas distintos, el lenguaje de las consultas no varía mucho, sino sería muy
difícil pasar de un sistema a otro y los SGBD no podrían competir entre ellos.
Lo que nos lleva a nuestra última cuestión, ¿qué tienen en común? ¿Qué son
esas siglas SQL en sus nombres?
4. El lenguaje SQL
A parte de los lenguajes de programación como Python, centrados en la creación
de los programas, los SGBD implementan su propia sintaxis o lenguaje propio
para realizar consultas y modificaciones en sus registros.
El lenguaje más utilizado en las bases de datos relacionales el lenguaje SQL
(Lenguaje de Consulta Estructurada), y es necesario aprenderlo si queremos
utilizar este tipo de bases de datos en nuestros programas.

3
1. SQLITE
SQLite es una biblioteca de software que proporciona un sistema de gestión de
bases de datos relacionales. El “lite” en SQLite significa ligero en términos de
configuración, administración de bases de datos y recursos necesarios.
SQLite tiene las siguientes características: autónomo, sin servidor, configuración
cero, transaccional.
Sin servidor
Normalmente, un RDBMS como MySQL, PostgreSQL, etc., requiere un servidor
independiente para funcionar. Las aplicaciones que quieren acceder al servidor
de la base de datos utilizan el protocolo TCP/IP para enviar y recibir solicitudes.
Esto se llama arquitectura cliente/servidor.

El siguiente diagrama ilustra la arquitectura cliente/servidor RDBMS:

Arquitectura de servidor de cliente RDBMS


SQLite NO funciona de esta manera.
SQLite NO requiere un servidor para ejecutarse.
La base de datos SQLite está integrada con la aplicación que accede a la base
de datos. Las aplicaciones interactúan con la base de datos SQLite, leen y
escriben directamente desde los archivos de la base de datos almacenados en
el disco.
El siguiente diagrama ilustra la arquitectura sin servidor de SQLite:

1
Autónomo
SQLite es autónomo, lo que significa que requiere un soporte mínimo del sistema
operativo o de una biblioteca externa. Esto hace que SQLite se pueda usar en
cualquier entorno, especialmente en dispositivos integrados como iPhones,
teléfonos Android, consolas de juegos, reproductores multimedia portátiles, etc.
SQLite está desarrollado usando ANSI-C. El código fuente está disponible como
un gran sqlite3.c y su archivo de encabezado sqlite3.h. Si desea desarrollar una
aplicación que use SQLite, solo necesita colocar estos archivos en su proyecto
y compilarlos con su código.
Configuración cero
Debido a la arquitectura sin servidor, no necesita "instalar" SQLite antes de
usarlo. No hay ningún proceso de servidor que deba configurarse, iniciarse y
detenerse.
Además, SQLite no utiliza ningún archivo de configuración.
Transaccional
Todas las transacciones en SQLite son totalmente compatibles con ACID.
Significa que todas las consultas y cambios son atómicos, consistentes, aislados
y duraderos. (Atomic, Consistent, Isolated and Durable)
En otras palabras, todos los cambios dentro de una transacción se realizan por
completo o no se realizan en absoluto, incluso cuando se produce una situación
inesperada, como un bloqueo de la aplicación, un corte de energía o un bloqueo
del sistema operativo.
Características distintivas de SQLite
SQLite usa tipos dinámicos para tablas. Significa que puede almacenar cualquier
valor en cualquier columna, independientemente del tipo de datos.
SQLite permite que una sola conexión de base de datos acceda a múltiples
archivos de base de datos simultáneamente. Esto trae muchas características
interesantes como unir tablas en diferentes bases de datos o copiar datos entre
bases de datos en un solo comando.
SQLite es capaz de crear bases de datos en memoria con las que es muy rápido
trabajar.

2
Instalación de SQLite
Para descargar SQLite, abra la página de descarga del sitio web oficial de SQlite.
• Primero, vaya al sitio web https://www.sqlite.org
• En segundo lugar, abra la página de descarga
https://www.sqlite.org/download.html

SQLite proporciona varias herramientas para trabajar en todas las plataformas,


por ejemplo, Windows, Linux y Mac. Debe seleccionar una versión apropiada
para descargar.
Por ejemplo, para trabajar con SQLite en Windows, descargue el programa de
shell de línea de comandos como se muestra en la captura de pantalla a
continuación.

El archivo descargado está en formato ZIP y su tamaño es bastante pequeño.


Ejecutar SQLite tools
Instalar SQLite es simple.
1. Primero, crear una carpeta nueva C:\sqlite.
2. Segundo, extraer el contenido del archivo descargado en la sección
anterior en la carpeta C:\sqlite . Se deberían ver los siguientes 3 programas en
la carpeta C:\sqlite:

Abrir la consola:

3
Ir a la carpeta C:\sqlite.
C:\cd c:\sqlite
C:\sqlite>
Tipear y ejecutar sqlite3, se debería ver la siguiente salida
C:\sqlite>sqlite3
SQLite version 3.29.0 2019-07-10 17:32:03
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
SQLite>
Tipeando el comando .help se pueden ver todos los comandos disponibles
sqlite> .help
.archive ... Manage SQL archives: ".archive --help" for details
.auth ON|OFF Show authorizer callbacks
.backup ?DB? FILE Backup DB (default "main") to FILE
.bail on|off Stop after hitting an error. Default OFF
.binary on|off Turn binary output on or off. Default OFF
.cd DIRECTORY Change the working directory to DIRECTORY
...
Para salir usar el comando .quit :
sqlite> .quit

c:\sqlite>
Instalar una herramienta de interfaz grafica
DB Browser for SQLite
https://sqlitebrowser.org/

4
Descargar el archivo necesario y seguir la instalación

5
1.Conectar a una base de datos
Hacer clic en Open Database y seleccionar el archivo .db

Mostrar las tablas de base de datos y su estructura


1. Tablas de la base
2. Estructura de la base
3. Indices
1. SELECT
La sentencia SELECT es una de las sentencias más utilizadas en SQL.
Consultar datos de una tabla usando la instrucción SELECT
A menudo usamos la declaración SELECT para consultar datos de una o más
tablas. La sintaxis de la sentencia SELECT es la siguiente:

SELECT lista_columnas
FROM tabla;

Aunque la cláusula SELECT aparece antes que la cláusula FROM, se evalúa


primero la cláusula FROM y luego la cláusula SELECT, por lo tanto:
• Primero, especificar la tabla de la que se desea obtener datos en la
cláusula FROM. Tener en cuenta que puede tener más de una tabla en la
cláusula FROM.
• En segundo lugar, especificar una columna o una lista de columnas
separadas por comas en la cláusula SELECT.
• Se utiliza el punto y coma (;) para terminar la declaración.

SELECT * FROM tabla;


Tener en cuenta que cuando desarrolla una aplicación, se debe controlar lo que
SQL devuelve a su aplicación. Suponiendo que una tabla tiene 3 columnas y usa
el asterisco (*) para recuperar los datos de las tres columnas.
Si alguien elimina una columna, su aplicación no estaría funcionando
correctamente, porque asume que se devuelven tres columnas y la lógica para
procesar esas tres columnas se rompería.
Si alguien agrega más columnas, su aplicación puede funcionar pero obtiene
más datos de los necesarios, lo que crea más sobrecarga de E/S entre la base
de datos y la aplicación.
Así que tratar de evitar usar el asterisco (*) como un buen hábito cuando use la
declaración SELECT.
2. ORDER BY
En SQL se almacena datos en las tablas en un orden no especificado. Significa
que las filas de la tabla pueden o no estar en el orden en que fueron insertadas.
Si se usa la declaración SELECT para consultar datos de una tabla, el orden de
las filas en el conjunto de resultados no se especifica.

1
Para ordenar el conjunto de resultados, agregue la cláusula ORDER BY a la
declaración SELECT de la siguiente manera:
SELECT
lista_columnas
FROM
tabla
ORDER BY
columna_1 ASC,
columna_2 DESC;
La cláusula ORDER BY viene después de la cláusula FROM. Permite ordenar el
conjunto de resultados en función de una o más columnas en orden ascendente
o descendente.
En esta sintaxis, coloca el nombre de la columna por la que desea ordenar
después de la cláusula ORDER BY seguida de la palabra clave ASC o DESC.
La palabra clave ASC significa ascendente.
Y la palabra clave DESC significa descender.
Si no especifica la palabra clave ASC o DESC, SQLite ordena el conjunto de
resultados usando la opción ASC. En otras palabras, ordena el conjunto de
resultados en orden ascendente de forma predeterminada.
En caso de que se desee ordenar el conjunto de resultados por varias columnas,
use una coma (,) para separar dos columnas. La cláusula ORDER BY ordena las
filas usando columnas o expresiones de izquierda a derecha. En otras palabras,
la cláusula ORDER BY ordena las filas usando la primera columna de la lista.
Luego, ordena las filas ordenadas usando la segunda columna, y así
sucesivamente.
Puede ordenar el conjunto de resultados utilizando una columna que no aparece
en la lista de selección de la cláusula SELECT.

3. ORDENANDO NULLS
En el mundo de las bases de datos, NULL es especial. Indica que la información
que falta o los datos no son aplicables.
NULL es especial porque no puede compararlo con otro valor. En pocas
palabras, si se desconocen las dos piezas de información, no se pueden
comparar.

2
NULL ni siquiera se puede comparar consigo mismo; NULL no es igual a sí
mismo, por lo que NULL = NULL siempre da como resultado falso.
Cuando se trata de ordenar, generalmente SQL considera que NULL es más
pequeño que cualquier otro valor.

Significa que aparecerán valores NULL al principio del conjunto de resultados si


usa ASC o al final del conjunto de resultados cuando usa DESC.
Existen en algunos motores opciones NULLS FIRST y NULLS LAST a la cláusula
ORDER BY. La opción NULLS FIRST especifica que los valores NULL
aparecerán al principio del conjunto de resultados, mientras que la opción NULLS
LAST coloca los valores NULL al final del conjunto de resultados.
4. DISTINCT
La cláusula DISTINCT es una cláusula opcional de la instrucción SELECT. La
cláusula DISTINCT le permite eliminar las filas duplicadas en el conjunto de
resultados.
La siguiente declaración ilustra la sintaxis de la cláusula DISTINCT:
SELECT DISTINCT lista_columnas
FROM tabla;

En esta sintaxis:
• Primero, la cláusula DISTINCT debe aparecer inmediatamente después
de la palabra clave SELECT.
• En segundo lugar, coloca una columna o una lista de columnas después
de la palabra clave DISTINCT. Si usa una columna, se usa valores en esa
columna para evaluar el duplicado. En caso de que use varias columnas, se usa
la combinación de valores en estas columnas para evaluar el duplicado.
SQLite considera los valores NULL como duplicados. Si usa la cláusula
DISTINCT con una columna que tiene valores NULL, se mantendrá una fila con
un valor NULL.
5. WHERE
La cláusula WHERE es una cláusula opcional de la instrucción SELECT. Aparece
después de la cláusula FROM como la siguiente declaración:
SELECT
Lista_columnas
FROM
tabla
WHERE

3
Condición_busqueda;

En este ejemplo, se agrega una cláusula WHERE a la instrucción SELECT para


filtrar las filas devueltas por la consulta. Al evaluar una declaración SELECT con
una cláusula WHERE, se llevan adelante los siguientes pasos:
• Primero, varifica la tabla en la cláusula FROM.
• Segundo, evalua las condiciones en la cláusula WHERE para obtener las
filas que cumplieron con estas condiciones.
• En tercer lugar, crea el conjunto de resultados final en función de las filas
del paso anterior con columnas en la cláusula SELECT.
La condición de búsqueda en el WHERE tiene la siguiente forma:
Expression_izquierda OPERADOR_COMPARASION expresión_derecha
Ejemplo:
WHERE column_1 = 100;
WHERE column_2 IN (1,2,3);
WHERE column_3 LIKE 'An%';
WHERE column_4 BETWEEN 10 AND 20;
6. OPERADORES DE COMPARACION
Un operador de comparación prueba si dos expresiones son iguales. La siguiente
tabla ilustra los operadores de comparación que puede usar para construir
expresiones:
Operator Meaning
= Equal to
<> or != Not equal to
< Less than
> Greater than
<= Less than or equal to
>= Greater than or equal to

7. OPERADORES LOGICOS
Los operadores lógicos permiten probar la verdad de algunas expresiones. Un
operador lógico devuelve 1, 0 o un valor NULL.
Operator Meaning
ALL returns 1 if all expressions are 1.

4
AND returns 1 if both expressions are 1, and 0 if one of the expressions is 0.
ANY returns 1 if any one of a set of comparisons is 1.
BETWEEN
returns 1 if a value is within a range.
EXISTS
returns 1 if a subquery contains any rows.
IN
returns 1 if a value is in a list of values.
LIKE
returns 1 if a value matches a pattern
NOT reverses the value of other operators such as NOT EXISTS, NOT IN, NOT
BETWEEN, etc.
OR returns true if either expression is 1

8. LIKE
A veces, es posible que no recuerde exactamente los datos que desea buscar.
En este caso, realiza una búsqueda inexacta utilizando el operador LIKE.
WHERE
columna LIKE patron

Existen dos comodines para construir patrones. Son el signo de porcentaje % y


el guión bajo _ :
El signo de porcentaje % comodín coincide con cualquier secuencia de cero o
más caracteres.
El guión bajo _ comodín coincide con cualquier carácter único.
El patrón s% que usa el comodín de signo de porcentaje (%) coincide con
cualquier cadena que comience con s, por ejemplo, sol y sebastián.
El patrón %er coincide con cualquier cadena que termine con er como peter,
comer, etc.
Y el patrón %per% coincide con cualquier cadena que contenga per, como por
pera y espera.
El patrón h_nt coincide con hunt, hint, etc. El patrón __pple coincide con topple,
suple, tipple, etc.
Tenga en cuenta que el operador LIKE no distingue entre mayúsculas y
minúsculas. Significa "A" LIKE "a" es verdadero.

5
Sin embargo, para los caracteres Unicode que no están en los rangos ASCII, el
operador LIKE distingue entre mayúsculas y minúsculas, por ejemplo, "Ä" LIKE
"ä" es falso.
9. Expresiones de escape
Si el patrón que desea hacer coincidir contiene % o _, debe usar un carácter de
escape en una cláusula ESCAPE opcional de la siguiente manera:
column_1 LIKE patrón ESCAPE expresión;
Cuando especifica la cláusula ESCAPE, el operador LIKE evaluará la expresión
que sigue a la palabra clave ESCAPE en una cadena que consta de un solo
carácter o un carácter de escape.

Luego, puede usar este carácter de escape en el patrón para incluir el signo de
porcentaje literal (%) o el guión bajo (_). El operador LIKE evalúa el signo de
porcentaje (%) o guión bajo (_) que sigue al carácter de escape como una
cadena literal, no como un carácter comodín.
Suponga que desea hacer coincidir la cadena 10% en una columna de una tabla.
Sin embargo, interpreta el símbolo de porcentaje % como el carácter comodín.
Por lo tanto, debe escapar este símbolo de porcentaje % usando un carácter de
escape:
columna_1 LIKE '%10\%%' ESCAPE '\';
En esta expresión, el operador LIKE interpreta el primer % y el último % por
ciento como comodines y el segundo signo de porcentaje como un símbolo de
porcentaje literal.
Tenga en cuenta que puede utilizar otros caracteres como carácter de escape,
por ejemplo, /, @, $.
10. IN
El operador IN le permite verificar si un valor está en una lista de una lista de
valores separados por comas.
WHERE
coumna IN (lista_valores);

Una lista de valores es una lista de valores fijos o un conjunto de resultados de


una sola columna devuelta por una subconsulta. El tipo de expresión devuelto y
los valores de la lista deben ser los mismos.
El operador IN devuelve verdadero o falso dependiendo de si la expresión
coincide con algún valor en una lista de valores o no. Para negar la lista de
valores, utiliza el operador NOT IN.
11. LIMIT

6
La cláusula LIMIT es una parte opcional de la instrucción SELECT. Utiliza la
cláusula LIMIT para restringir el número de filas devueltas por la consulta.
Por ejemplo, una instrucción SELECT puede devolver un millón de filas. Sin
embargo, si solo necesita las primeras 10 filas en el conjunto de resultados,
puede agregar la cláusula LIMIT a la declaración SELECT para recuperar 10
filas.
A continuación se ilustra la sintaxis de la cláusula LIMIT.
SELECT
Lista_columnas
FROM
tabla
LIMIT nro_filas;

Nro_filas es un entero positivo que especifica el número de filas devueltas.


12. LIMIT y ORDER BY
Siempre debe usar la cláusula LIMIT con la cláusula ORDER BY. Porque si desea
obtener una cantidad de filas en un orden específico, no en un orden no
especificado.

La cláusula ORDER BY aparece antes de la cláusula LIMIT en la instrucción


SELECT. SQLite ordena el conjunto de resultados antes de obtener el número
de filas especificado en la cláusula LIMIT.
SELECT
Lista_columnas
FROM
tabla
ORDER BY columna_1
LIMIT nro_filas;

Obtener el enésimo valor más alto y el más bajo


Puede usar las cláusulas ORDER BY y LIMIT para obtener las enésimas filas de
valor más alto o más bajo, siguiendo los siguientes pasos
• Primero, use ORDER BY para ordenar el conjunto de resultados en orden
ascendente en caso de que desee obtener el enésimo valor más bajo, o en orden
descendente si desea obtener el enésimo valor más alto.

7
• En segundo lugar, use la cláusula LIMIT OFFSET para obtener la enésima
fila más alta o la enésima más baja.
SELECT
Lista_columnas
FROM
tabla
ORDER BY
Columna_1 DESC
LIMIT 1 OFFSET 1;

13. BETWEEN
El operador BETWEEN es un operador lógico que prueba si un valor está dentro
del rango de valores. Si el valor está en el rango especificado, el operador
BETWEEN devuelve verdadero. El operador BETWEEN se puede utilizar en la
cláusula WHERE de las instrucciones SELECT, DELETE, UPDATE y REPLACE
Expresion_test BETWEEN expression_bajo AND Expresion_alto
En esta sintaxis:
Expresion_test es una expresión para probar en el rango definido por
expression_bajo y Expresion_alto.
expresión_baja y expresión_alta es cualquier expresión válida que especifique
los valores alto y bajo del rango. expresión_baja debe ser menor o igual que
expresión_alta, o BETWEEN siempre devuelve falso.
La palabra clave AND es un marcador de posición que indica que Expresion_test
debe estar dentro del rango especificado por expresión_baja y expresión_alta.
Tenga en cuenta que el operador BETWEEN es inclusivo. Devuelve verdadero
cuando Expresion_test es menor o igual que expresión_alta y mayor o igual que
el valor de expresión_baja:
Expresion_test >= expresión_baja AND Expresion_test <=
expresión_alta
Para especificar un rango exclusivo, utilice los operadores mayor que (>) y menor
que (<).
Tenga en cuenta que si cualquier entrada al operador BETWEEN es NULL, el
resultado es NULL o desconocido para ser precisos.
Para negar el resultado del operador BETWEEN, utilice el operador NOT
BETWEEN de la siguiente manera:
Expresion_test NOT BETWEEN expression_bajo AND
Expresion_alto

8
14. IS NULL
NULL es especial. Indica que un dato es desconocido o no aplicable.
NULL no es igual a nada, ni siquiera al número cero, una cadena vacía, etc.
Especialmente, NULL no es igual a sí mismo. La siguiente expresión devuelve 0:
NULL = NULL
Para comprobar si un valor es NULL o no, utilice el operador IS NULL en su lugar:
{ columna | expresión } IS NULL;
El operador IS NULL devuelve 1 si la columna o expresión se evalúa como NULL.

9
1. JOINS

1.1. INNER JOIN


En las bases de datos relacionales, los datos a menudo se distribuyen en
muchas tablas relacionadas. Una tabla se asocia con otra tabla mediante claves
foráneas.
Para consultar datos de varias tablas, utiliza la cláusula INNER JOIN. La cláusula
INNER JOIN combina columnas de tablas correlacionadas.
Suponga que tiene dos tablas: A y B.
A tiene columnas a1, a2 y f. B tiene columnas b1, b2 y f. La tabla A se vincula a
la tabla B mediante una columna de clave externa denominada f.
A continuación, se ilustra la sintaxis de la cláusula de unión interna:
SELECT a1, a2, b1, b2
FROM A
INNER JOIN B on B.f = A.f;
Para cada fila de la tabla A, la cláusula INNER JOIN compara el valor de la
columna f con el valor de la columna f de la tabla B. Si el valor de la columna f
en la tabla A
es igual al valor de la columna f en la tabla B, combina datos de las columnas
a1, a2, b1, b2 e incluye esta fila en el conjunto de resultados.
En otras palabras, la cláusula INNER JOIN devuelve filas de la tabla A que tiene
la fila correspondiente en la tabla B.
Esta lógica se aplica si te unes a más de 2 tablas.
Vea el siguiente ejemplo.

1
Solo las filas de la tabla A: (a1,1), (a3,3) tienen las filas correspondientes en la
tabla B (b1,1), (b2,3) se incluyen en el conjunto de resultados.
El siguiente diagrama ilustra la cláusula INNER JOIN:

1.2. LEFT JOIN


Similar a la cláusula INNER JOIN, la cláusula LEFT JOIN es una cláusula
opcional de la instrucción SELECT. Utiliza la cláusula LEFT JOIN para consultar
datos de varias tablas relacionadas.
Supongamos que tenemos dos tablas: A y B.
A tiene m y f columnas.

B tiene n y f columnas.

Para realizar una unión entre A y B usando la cláusula LEFT JOIN, use la
siguiente declaración:
SELECT
a,
b
FROM
A
LEFT JOIN B ON A.f = B.f
WHERE search_condition;
La expresión A.f = B.f es una expresión condicional. Además del operador de
igualdad (=), puede utilizar otros operadores de comparación como mayor que
(>), menor que (<), etc.
La instrucción devuelve un conjunto de resultados que incluye:
Filas de la tabla A (tabla de la izquierda) que tienen filas correspondientes en la
tabla B.
2
Las filas de la tabla A y las filas de la tabla B se rellenan con valores NULL en
caso de que la fila de la tabla A no tenga filas correspondientes en la tabla B.
En otras palabras, todas las filas de la tabla A se incluyen en el conjunto de
resultados, ya sea que haya filas coincidentes en la tabla B o no.
En caso de que tenga una cláusula WHERE en la declaración, la condición de
búsqueda en la cláusula WHERE se aplica después de que se complete la
coincidencia de la cláusula LEFT JOIN.
Consulte la siguiente ilustración de la cláusula LEFT JOIN entre las tablas A y B.

Todas las filas de la tabla A se incluyen en el conjunto de resultados.


Debido a que la segunda fila (a2,2) no tiene una fila correspondiente en la tabla
B, la cláusula LEFT JOIN crea una fila falsa llena de NULL.
El siguiente diagrama de Venn ilustra la cláusula LEFT JOIN.

Se observa que LEFT OUTER JOIN es lo mismo que LEFT JOIN.


1.3. FULL OUTER JOIN
En teoría, el resultado de FULL OUTER JOIN es una combinación de LEFT JOIN
y RIGHT JOIN. El conjunto de resultados de la combinación externa completa
tiene valores NULL para cada columna de la tabla que no tiene una fila
coincidente en la otra tabla. Para las filas coincidentes, FULL OUTER JOIN
produce una sola fila con valores de las columnas de las filas en ambas tablas.

3
La siguiente imagen ilustra el resultado de la cláusula FULL OUTER JOIN:

En algunos motores de base de datos, no es soportado pero puede ser emulado


con UNION y LEFT JOIN
SELF JOIN

La unión automática es un tipo especial de unión que le permite unir una tabla a
sí misma utilizando la cláusula LEFT JOIN o INNER JOIN. Utiliza la unión
automática para crear un conjunto de resultados que une las filas con las otras
filas dentro de la misma tabla.
Debido a que no puede hacer referencia a la misma tabla más de una en una
consulta, debe usar un alias de tabla para asignarle un nombre diferente cuando
usa la autocombinación.
La autocombinación compara valores de las mismas o diferentes columnas en
la misma tabla. Solo una tabla está involucrada en la autocombinación.
A menudo utiliza la autocombinación para consultar la relación padre/hijo
almacenada en una tabla o para obtener totales acumulados.

2. AGRUPAMIENTO
2.1. GROUP BY
La cláusula GROUP BY es una cláusula opcional de la instrucción SELECT. La
cláusula GROUP BY un grupo seleccionado de filas en filas de resumen por
valores de una o más columnas.
La cláusula GROUP BY devuelve una fila para cada grupo. Para cada grupo,
puede aplicar una función agregada como MIN, MAX, SUM, COUNT o AVG para
proporcionar más información sobre cada grupo.
La siguiente declaración ilustra la sintaxis de la cláusula GROUP BY de
SQLite. SELECT column_1,
aggregate_function(column_2) FROM
table
GROUP BY column_1, column_2;

4
La cláusula GROUP BY viene después de la cláusula FROM de la instrucción
SELECT. En caso de que una declaración contenga una cláusula WHERE, la
cláusula GROUP BY debe ir después de la cláusula WHERE.
Después de la cláusula GROUP BY hay una columna o una lista de columnas
separadas por comas que se utilizan para especificar el grupo.
2.2. HAVING
La cláusula SQLite HAVING es una cláusula opcional de la declaración SELECT.
La cláusula HAVING especifica una condición de búsqueda para un grupo.
A menudo usa la cláusula HAVING con la cláusula GROUP BY. La cláusula
GROUP BY agrupa un conjunto de filas en un conjunto de filas o grupos de
resumen. Luego, la cláusula HAVING filtra grupos en función de una condición
específica.
Si usa la cláusula HAVING, debe incluir la cláusula GROUP BY; de lo contrario,
obtendrá el siguiente error:
Error: a GROUP BY clause is required before HAVING
Tenga en cuenta que la cláusula HAVING se aplica después de la cláusula
GROUP BY, mientras que la cláusula WHERE se aplica antes de la cláusula
GROUP BY.
SELECT
column_1,
column_2,
aggregate_function (column_3)
FROM
table
GROUP BY
column_1,
column_2
HAVING
search_condition;
En esta sintaxis, la cláusula HAVING evalúa la condición de búsqueda para cada
grupo como una expresión booleana. Solo incluye un grupo en el conjunto de
resultados final si la evaluación es verdadera.

3. CONJUNTOS /
3.1. UNION

5
A veces, necesita combinar datos de varias tablas en un conjunto de resultados
completo. Puede ser para tablas con datos similares dentro de la misma base
de datos o tal vez necesite combinar datos similares de varias bases de datos.
Para combinar filas de dos o más consultas en un único conjunto de resultados,
utilice el operador SQLite UNION. A continuación se ilustra la sintaxis básica del
operador UNION:
query_1
UNION [ALL]
query_2
UNION [ALL]
query_3
...;
Los operadores UNION y UNION ALL combinan filas de conjuntos de resultados
en un único conjunto de resultados. El operador UNION elimina las filas
duplicadas, mientras que el operador UNION ALL no lo hace.
Debido a que el operador UNION ALL no elimina las filas duplicadas, se ejecuta
más rápido que el operador UNION.
Las siguientes son reglas para unir datos:
• El número de columnas en todas las consultas debe ser el mismo.
• Las columnas correspondientes deben tener tipos de datos compatibles.
• Los nombres de columna de la primera consulta determinan los nombres
de columna del conjunto de resultados combinado.
• Las cláusulas GROUP BY y HAVING se aplican a cada consulta
individual, no al conjunto de resultados final.
• La cláusula ORDER BY se aplica al conjunto de resultados combinado,
no dentro del conjunto de resultados individual.
Tenga en cuenta que la diferencia entre UNION y JOIN, por ejemplo, INNER
JOIN o LEFT JOIN, es que la cláusula JOIN combina columnas de varias tablas
relacionadas, mientras que UNION combina filas de varias tablas similares.
Suponiendo que se tiene las siguientes tablas con los valores insertados:
CREATE TABLE t1(
v1 INT
);
INSERT INTO t1(v1)
VALUES(1),(2),(3);
CREATE TABLE t2(

6
v2 INT
);
INSERT INTO t2(v2)
VALUES(2),(3),(4);
Al aplicar el operador UNION
SELECT v1
FROM t1
UNION
SELECT v2
FROM t2;

Al aplicar el operador UNION ALL


SELECT v1
FROM t1
UNION ALL
SELECT v2
FROM t2;

3.2. EXCEPT
El operador EXCEPT de SQLite compara los conjuntos de resultados de dos
consultas y devuelve filas distintas de la consulta de la izquierda que no genera
la consulta de la derecha.

7
A continuación se muestra la sintaxis del operador EXCEPT:
SELECT select_list1
FROM table1
EXCEPT
SELECT select_list2
FROM table2
Esta consulta debe ajustarse a las siguientes reglas:
• Primero, el número de columnas en las listas de selección de ambas
consultas debe ser el mismo.
• En segundo lugar, el orden de las columnas y sus tipos deben ser
comparables.
Las siguientes declaraciones crean dos tablas t1 y t2 e insertan algunos datos
en ambas tablas:
CREATE TABLE t1( v1 INT
);

INSERT INTO t1(v1)


VALUES(1),(2),(3);

CREATE TABLE t2(


v2 INT
);
INSERT INTO t2(v2)
VALUES(2),(3),(4);
Al ejecutar EXCEPT
SELECT v1
FROM t1
EXCEPT
SELECT v2
FROM t2;

8
3.3. INTERSECT
El operador INTERSECT compara los conjuntos de resultados de dos consultas
y devuelve filas distintas que generan ambas consultas.
A continuación se ilustra la sintaxis del operador INTERSECT:
SELECT select_list1
FROM table1
INTERSECT
SELECT select_list2
FROM table2
Las reglas básicas para combinar los conjuntos de resultados de dos consultas
son las siguientes:
• Primero, el número y el orden de las columnas en todas las consultas
debe ser el mismo.
• En segundo lugar, los tipos de datos deben ser comparables.
Para la demostración, crearemos dos tablas t1 y t2 e insertaremos algunos datos
en ambas:
CREATE TABLE t1(
v1 INT
);

INSERT INTO t1(v1)


VALUES(1),(2),(3);

CREATE TABLE t2(


v2 INT
);
INSERT INTO t2(v2)

9
VALUES(2),(3),(4);
Al aplicar INTERSECT
SELECT v1
FROM t1
INTERSECT
SELECT v2
FROM t2;

10
1. SUBCONSULTAS

1.1. SUBCONSULTAS ANIDADAS


Una subconsulta es una sentencia SELECT anidada en otra sentencia. Vea la
siguiente declaración.
SELECT column_1
FROM table_1
WHERE column_1 = (
SELECT column_1
FROM table_2
);
La siguiente consulta es la consulta externa:
SELECT column_1
FROM table_1
WHERE colum_1 =
Y la siguiente consulta es la subconsulta.
(SELECT column_1
FROM table_2)
Debe utilizar un par de paréntesis para encerrar una subconsulta. Tenga en
cuenta que puede anidar una subconsulta dentro de otra subconsulta con cierta
profundidad.
Por lo general, una subconsulta devuelve una sola fila como un valor atómico,
aunque puede devolver varias filas para comparar valores con el operador IN.
Puede utilizar una subconsulta en las cláusulas SELECT, FROM, WHERE y
JOIN.
1.2. SUBCONSULTAS RELACIONADAS
Todas las subconsultas que has visto hasta ahora se pueden ejecutar de forma
independiente. En otras palabras, no depende de la consulta externa.
La subconsulta correlacionada es una subconsulta que usa los valores de la
consulta externa. A diferencia de una subconsulta ordinal, una subconsulta
correlacionada no se puede ejecutar de forma independiente.
La subconsulta correlacionada no es eficiente porque se evalúa para cada fila
procesada por la consulta externa.

1
SELECT albumid,
title
FROM albums
WHERE 10000000 > (
SELECT sum(bytes)
FROM tracks
WHERE tracks.AlbumId =
albums.AlbumId
)
ORDER BY title;
2. EXISTS
El operador EXISTS es un operador lógico que verifica si una subconsulta
devuelve alguna fila.
Esta es la sintaxis básica del operador EXISTS:
EXISTS(subquery)
En esta sintaxis, la subconsulta es una instrucción SELECT que devuelve cero o
más filas.
Si la subconsulta devuelve una o más filas, el operador EXISTS devuelve
verdadero. De lo contrario, el operador EXISTS devuelve falso o NULL.
Tenga en cuenta que si la subconsulta devuelve una fila con NULL, el resultado
del operador EXISTS sigue siendo verdadero porque el conjunto de resultados
contiene una fila con NULL.
Para negar el operador EXISTE, utilice el operador NO EXISTE de la siguiente
manera:
NOT EXISTS (subquery)
El operador NOT EXISTS devuelve verdadero si la subconsulta no devuelve
ninguna fila.

3. CASE
La expresión CASE evalúa una lista de condiciones y devuelve una expresión
basada en el resultado de la evaluación.
La expresión CASE es similar a la declaración IF-THEN-ELSE en otros lenguajes
de programación.
Puede utilizar la expresión CASE en cualquier cláusula o declaración que acepte
una expresión válida. Por ejemplo, puede usar la expresión CASE en cláusulas

2
como WHERE, ORDER BY, HAVING, SELECT y declaraciones como SELECT,
UPDATE y DELETE.
3.1. CASE simple
La expresión CASE simple compara una expresión con una lista de expresiones
para devolver el resultado.
CASE case_expression
WHEN when_expression_1 THEN result_1
WHEN when_expression_2 THEN result_2
...
[ ELSE result_else ]
END

La expresión CASE simple compara case_expression con la expresión que


aparece en la primera cláusula WHEN, when_expression_1, para la igualdad.
Si case_expression es igual a when_expression_1, el CASE simple devuelve la
expresión en la cláusula THEN correspondiente, que es result_1.
De lo contrario, la expresión CASE simple compara case_expression con la
expresión en la siguiente cláusula WHEN.
En caso de que ninguna case_expression coincida con when_expression_n, la
expresión CASE devuelve el result_else en la cláusula ELSE. Si omite la cláusula
ELSE, la expresión CASE devuelve NULL.
La expresión CASE devuelve el resultado y deja de evaluar otras condiciones
tan pronto como encuentra una coincidencia.
3.2. CASE BUSQUEDA
La expresión CASE busqueda evalúa una lista de expresiones para decidir el
resultado. Tenga en cuenta que la expresión CASE simple solo compara la
igualdad, mientras que la expresión CASE busqueda puede usar cualquier forma
de comparación.
CASE
WHEN bool_expression_1 THEN result_1
WHEN bool_expression_2 THEN result_2
[ ELSE result_else ]
END

La expresión CASE busqueda evalúa las expresiones booleanas en la secuencia


especificada y devuelve el resultado correspondiente si la expresión se evalúa
como verdadera.

3
En caso de que ninguna expresión se evalúe como verdadera, la expresión
CASE busqueda devuelve la expresión en la cláusula ELSE si se especifica. Si
omite la cláusula ELSE, la expresión CASE busqueda devuelve NULL.
Similar a la expresión CASE simple, la expresión CASE busqueda detiene la
evaluación cuando se cumple una condición.

4. MANEJO DE DATOS
4.1. INSERT
Para insertar datos en una tabla, utiliza la instrucción INSERT. SQLd proporciona
varias formas de instrucciones INSERT que le permiten insertar una sola fila,
varias filas y valores predeterminados en una tabla.
Además, puede insertar una fila en una tabla utilizando los datos proporcionados
por una instrucción SELECT.
Para insertar una sola fila en una tabla, utilice la siguiente forma de la instrucción
INSERT:
INSERT INTO table (column1,column2 ,..)
VALUES( value1, value2 ,...);

Examinemos la instrucción INSERT con más detalle:


• Primero, especifique el nombre de la tabla en la que desea insertar
datos después de las palabras clave INSERT INTO.
• En segundo lugar, agregue una lista de columnas separadas por comas
después del nombre de la tabla. La lista de columnas es opcional. Sin
embargo, es una buena práctica incluir la lista de columnas después del
nombre de la tabla.
• En tercer lugar, agregue una lista de valores separados por comas
después de la palabra clave VALUES. Si omite la lista de columnas,
debe especificar valores para todas las columnas en la lista de valores.
El número de valores en la lista de valores debe ser el mismo que el
número de columnas en la lista de columnas.
Para insertar varias filas en una tabla, usa la siguiente forma de la instrucción
INSERT:
+

Cada lista de valores que sigue a la cláusula VALUES es una fila que se insertará
en la tabla.
Para insertar varias filas en una tabla como resultado de una consulta SELECT:
INSERT INTO table
SELECT column_name
FROM table2;
Aplican las mismas reglas respecto a las columnas y valores

4
4.2. UPDATE
Para actualizar los datos existentes en una tabla, utiliza la instrucción UPDATE.
UPDATE table
SET column_1 = new_value_1,
column_2 = new_value_2
WHERE
search_condition
ORDER column_or_expression
LIMIT row_count OFFSET
offset;

En esta sintaxis:
• Primero, especifique la tabla donde desea actualizar después de la
cláusula UPDATE.
• En segundo lugar, establezca un nuevo valor para cada columna de la
tabla en la cláusula SET.
• En tercer lugar, especifique filas para actualizar usando una condición
en la cláusula WHERE. La cláusula WHERE es opcional. Si lo omite, la
instrucción UPDATE actualizará los datos en todas las filas de la tabla.
Finalmente, use las cláusulas ORDER BY y LIMIT en la declaración UPDATE
para especificar el número de filas para actualizar.
Tenga en cuenta que si usa un valor negativo en la cláusula LIMIT, SQLite asume
que no hay límite y actualiza todas las filas que cumplen la condición en la
cláusula WHERE anterior.
La cláusula ORDER BY siempre debe ir con la cláusula LIMIT para especificar
exactamente qué filas se actualizarán. De lo contrario, nunca sabrá qué fila se
actualizará realmente; porque sin la cláusula ORDER BY, no se especifica el
orden de las filas en la tabla.
4.3. DELETE
Ha aprendido cómo insertar una nueva fila en una tabla y actualizar los datos
existentes de una tabla. A veces, necesita eliminar filas de una tabla. En este
caso, utiliza la instrucción DELETE.
La instrucción DELETE de SQL le permite eliminar una fila, varias filas y todas
las filas de una tabla. La sintaxis de la instrucción DELETE es la siguiente:
DELETE FROM table WHERE

search_condition; En esta
sintaxis:

5
• Primero, especifique el nombre de la tabla de la que desea eliminar filas
después de las palabras clave DELETE FROM.
• En segundo lugar, agregue una condición de búsqueda en la cláusula
WHERE para identificar las filas que desea eliminar. La cláusula
WHERE es una parte opcional de la instrucción DELETE. Si omite la
cláusula WHERE, la instrucción DELETE eliminará todas las filas de la
tabla.
4.4. REPLACE
La idea de la declaración REPLACE es que cuando ocurre una violación de
restricción UNIQUE o PRIMARY KEY, hace lo siguiente:
Primero, elimine la fila existente que causa una violación de restricción.
En segundo lugar, inserte una nueva fila.
En el segundo paso, si se produce una infracción de restricción, por ejemplo,
restricción NOT NULL, la declaración REPLACE cancelará la acción y revertirá
la transacción.
REPLACE INTO table(column_list)
VALUES(value_list);

Observe que la instrucción REPLACE significa INSERTAR o REEMPLAZAR, no


INSERTAR o ACTUALIZAR.

5. TRANSACCIONES
SQLite es una base de datos transaccional en la que todos los cambios y
consultas son atómicos, consistentes, aislados y duraderos (ACID).
SQLite garantiza que todas las transacciones cumplen con ACID incluso si la
transacción se interrumpe por un bloqueo del programa, un volcado del sistema
operativo o un corte de energía en la computadora.
• ATOMIC: una transacción debe ser atómica. Significa que un cambio no
se puede dividir en otros más pequeños. Cuando confirma una
transacción, se aplica toda la transacción o no.
• CONSISTENT: una transacción debe asegurarse de cambiar la base de
datos de un estado válido a otro. Cuando se inicia una transacción y se
ejecuta una declaración para modificar datos, la base de datos se vuelve
inconsistente. Sin embargo, cuando la transacción se confirma o revierte,
es importante que la transacción mantenga la coherencia de la base de
datos.
• ISOLATED: una transacción pendiente realizada por una sesión debe
aislarse de otras sesiones. Cuando una sesión inicia una transacción y
ejecuta la declaración INSERT o UPDATE para cambiar los datos, estos
cambios solo son visibles para la sesión actual, no para otros. Por otro
lado, los cambios realizados por otras sesiones después de iniciada la
transacción no debería ser visibles para la sesión actual.

6
• DURABLE: si una transacción se confirma con éxito, los cambios deben
ser permanentes en la base de datos, independientemente de la
condición, como un corte de energía o un bloqueo del programa. Por el
contrario, si el programa falla antes de que se confirme la transacción, el
cambio no debería persistir.
De forma predeterminada, SQLite funciona en modo de confirmación automática.
Significa que para cada comando, SQLite inicia, procesa y confirma la
transacción automáticamente.
Para iniciar una transacción explícitamente, utilice los siguientes pasos:
BEGIN TRANSACTION;
Después de ejecutar la declaración BEGIN TRANSACTION, la transacción está
abierta hasta que se confirme o revierta explícitamente.
En segundo lugar, emita sentencias SQL para seleccionar o actualizar datos en
la base de datos. Tenga en cuenta que el cambio solo es visible para la sesión
actual (o cliente).
En tercer lugar, confirme los cambios en la base de datos utilizando la instrucción
COMMIT o COMMIT TRANSACTION
COMMIT;
Si no desea guardar los cambios, puede retroceder utilizando la instrucción
ROLLBACK o ROLLBACK TRANSACTION:
ROLLBACK;

7
1. DEFINICION DE DATOS
1.1. Tipos de datos de SQLITE
Otros sistemas de bases de datos como MySQL y PostgreSQL usan escritura
estática. Significa que cuando declara una columna con un tipo de datos
específico, esa columna solo puede almacenar datos del tipo de datos
declarado.
A diferencia de otros sistemas de bases de datos, SQLite utiliza un sistema de
tipo dinámico. En otras palabras, un valor almacenado en una columna
determina su tipo de datos, no el tipo de datos de la columna.
Además, no tiene que declarar un tipo de datos específico para una columna
cuando crea una tabla. En caso de que declare una columna con el tipo de datos
entero, puede almacenar cualquier tipo de datos, como texto y BLOB, SQLite no
se quejará de esto.
SQLite proporciona cinco tipos de datos primitivos a los que se hace referencia
como clases de almacenamiento.
Las clases de almacenamiento describen los formatos que utiliza SQLite para
almacenar datos en el disco. Una clase de almacenamiento es más general que
un tipo de datos, por ejemplo, la clase de almacenamiento INTEGER incluye 6
tipos diferentes de enteros. En la mayoría de los casos, puede usar clases de
almacenamiento y tipos de datos indistintamente.
La siguiente tabla ilustra 5 clases de almacenamiento en SQLite:

Tipo Significado

NULL NULL informacion desconocida

INTEGE Los valores enteros son números enteros (ya sean positivos o
R negativos). Un número entero puede tener tamaños variables como 1,
2,3, 4 u 8 bytes.

REAL Los valores reales son números reales con valores decimales que usan
flotantes de 8 bytes.

TEXT TEXTO se utiliza para almacenar datos de caracteres. La longitud


máxima de TEXTO es ilimitada. SQLite admite varias codificaciones de
caracteres.

BLOB BLOB significa un gran objeto binario que puede almacenar cualquier
tipo de datos. El tamaño máximo de BLOB es, teóricamente, ilimitado.

1
2. CREATE TABLE
Para crear una nueva tabla en SQL, use la declaración CREATE TABLE usando
la siguiente sintaxis:
CREATE TABLE [IF NOT EXISTS]
[schema_name].table_name ( column_1 data_type
PRIMARY KEY, column_2 data_type NOT NULL,
column_3 data_type DEFAULT 0,
table_constraints
) [WITHOUT ROWID];
En esta sintaxis:
• Primero, especifique el nombre de la tabla que desea crear después de
las palabras clave CREATE TABLE.
• En segundo lugar, use la opción IF NOT EXISTS para crear una nueva
tabla si no existe. Si intenta crear una tabla que ya existe sin utilizar la
opción IF NOT EXISTS, se producirá un error.
• En tercer lugar, especifique opcionalmente el schema_name al que
pertenece la nueva tabla. El esquema puede ser la base de datos
principal, la base de datos temporal o cualquier base de datos.
• Cuarto, especifique la lista de columnas de la tabla. Cada columna tiene
un nombre, un tipo de datos y la restricción de la columna. Se admite las
restricciones de columna PRIMARY KEY, UNIQUE, NOT NULL y CHECK.
• En quinto lugar, especifique las restricciones de la tabla, como PRIMARY
KEY, FOREIGN KEY, UNIQUE y CHECK.
Tenga en cuenta que la clave principal de una tabla es una columna o un grupo
de columnas que identifican de forma única cada fila de la tabla.
3. ALTER TABLE
Para hacer cambios en una tabla se utiliza la declaración ALTER TABLE,
generalmente se utiliza para lo siguiente:
• Cambiar el nombre de una tabla.
• Agregar una nueva columna a una tabla.
• Cambiar el nombre de una columna

Para cambiar el nombre de una tabla, utilice la siguiente instrucción ALTER


TABLE RENAME TO:
ALTER TABLE existing_table
RENAME TO new_table;
Estos son puntos importantes que debe saber antes de cambiar el nombre de
una tabla:

2
• ALTER TABLE solo cambia el nombre de una tabla dentro de una base
de datos. No puede usarlo para mover la tabla entre las bases de datos
adjuntas.
• Los objetos de la base de datos, como índices y triggers asociados con la
tabla, se asociarán con la nueva tabla.
• Si se hace referencia a una tabla mediante vistas o declaraciones en
disparadores, debe cambiar manualmente la definición de vistas y
triggers.
Puede usar la declaración ALTER TABLE para agregar una nueva columna a una
tabla existente. En este escenario, seagrega la nueva columna al final de la lista
de columnas existente.
ALTER TABLE table_name
ADD COLUMN column_definition;
Hay algunas restricciones en la nueva columna:
• La nueva columna no puede tener una restricción UNIQUE o PRIMARY
KEY.
• Si la nueva columna tiene una restricción NOT NULL, debe especificar un
valor predeterminado para la columna que no sea un valor NULL.
• La nueva columna no puede tener un valor predeterminado de
CURRENT_TIMESTAMP, CURRENT_DATE y CURRENT_TIME, o una
expresión.
• Si la nueva columna es una clave externa y la verificación de restricción
de clave externa está habilitada, la nueva columna debe aceptar un valor
predeterminado NULL.
Para cambiar el nombre de una columna usando la declaración ALTER TABLE
RENAME COLUMN
ALTER TABLE table_name
RENAME COLUMN current_name TO new_name;
En esta sintaxis:
Primero, especifique el nombre de la tabla después de las palabras clave
ALTER TABLE.
• En segundo lugar, especifique el nombre de la columna a la que desea
cambiar el nombre después de las palabras clave RENAME COLUMN y
el nuevo nombre después de la palabra clave TO.
4. DROP
Para eliminar una tabla en una base de datos, use la instrucción DROP TABLE
de SQL. La declaración es simple de la siguiente manera:
DROP TABLE [IF EXISTS] [schema_name.]table_name;

3
En esta sintaxis, especifica el nombre de la tabla que desea eliminar después de
las palabras clave DROP TABLE.
Generalmente se permite eliminar solo una tabla a la vez. Para eliminar varias
tablas, debe emitir varias instrucciones DROP TABLE.
Si elimina una tabla que no existe, SQL emite un error. Si usa la opción IF
EXISTS, entonces SQL elimina la tabla solo si la tabla existe; de lo contrario,
simplemente ignora la declaración y no hace nada.
Si desea eliminar una tabla en una base de datos específica, use
[schema_name.] explícitamente.
En caso de que la tabla tenga objetos dependientes, como triggers e índices, la
declaración DROP TABLE también elimina todos los objetos dependientes.
La sentencia DROP TABLE realiza una sentencia DELETE implícita antes de
descartar la tabla. Sin embargo, la instrucción DROP TABLE elimina los triggers
asociados con la tabla antes de ejecutar la instrucción DELETE implícita, por lo
tanto, los triggers de eliminación no se activarán.
Si las restricciones de clave externa están habilitadas y realiza la declaración
DROP TABLE, antes de que SQL realice la declaración DELETE implícita, realiza
la verificación de restricciones de clave externa. Si se produce una violación de
restricción de clave externa, SQL emite un mensaje de error y no eliminará la
tabla.
Observe que la declaración DROP TABLE elimina la tabla de la base de datos y
el archivo en el disco por completo. No podrá deshacer ni recuperarse de esta
acción. Por lo tanto, debe realizar la instrucción DROP TABLE con especial
precaución.

5. CONSTRAINTS
5.1. PRIMARY KEY
Una PRIMARY KEY es una columna o grupo de columnas que se utiliza para
identificar la unicidad de las filas de una tabla. Cada tabla tiene una y sólo una
clave principal.
Se permite definir la clave principal de dos maneras:
Primero, si la clave principal tiene solo una columna, use la restricción de
columna PRIMARY KEY para definir la clave principal de la siguiente manera:
CREATE TABLE table_name( column_1 INTEGER NOT NULL PRIMARY
KEY,
...
);
En segundo lugar, en caso de que la clave principal consista en dos o más
columnas, utilice la restricción de la tabla PRIMARY KEY para definir la clave
principal, como se muestra en la siguiente declaración.

4
CREATE TABLE table_name( column_1 INTEGER NOT NULL,
column_2 INTEGER NOT NULL,
...
PRIMARY KEY(column_1,column_2,...)
);
En el estándar SQL, la columna de clave principal no debe contener valores
NULL. Significa que la columna de clave principal tiene una restricción NOT
NULL implícita.
5.2. FOREING KEY
Restricción de clave externa para hacer cumplir las relaciones entre tablas
relacionadas.
La restricción FOREIGN KEY se usa para evitar acciones que destruirían enlaces
entre tablas.
Una FOREIGN KEY es un campo (o colección de campos) en una tabla, que se
refiere a la PRIMARY KEY en otra tabla.
La tabla con la clave externa se denomina tabla secundaria, y la tabla con la
clave principal se denomina tabla principal o de referencia.
Mira las dos tablas siguientes:
Tabla Persona
PersonID LastName FirstName Age
1 Hansen Ola 30
2 Svendson Tove 23
3 Pettersen Kari 20
Tabla Orden
OrderID OrderNumber PersonID
1 77895 3
2 44678 3
3 22456 2
4 24562 1
Observe que la columna "PersonID" en la tabla "Pedidos" apunta a la columna
"PersonID" en la tabla "Personas".
La columna "PersonID" en la tabla "Personas" es la PRIMARY KEY en la tabla
"Personas".
La columna "PersonID" en la tabla "Pedidos" es una FOREIGN KEY en la tabla
"Pedidos".

5
La restricción FOREIGN KEY evita que se inserten datos no válidos en la
columna de clave externa, porque tiene que ser uno de los valores contenidos
en la tabla principal. Sintaxis
FOREIGN KEY (foreign_key_columns)
REFERENCES parent_table(parent_key_columns)
ON UPDATE action
ON DELETE action;
¿Qué sucedería si elimina una fila en la tabla principal? ¿Deberían eliminarse
también todas las filas correspondientes de la tabla de secundaria? Las mismas
preguntas a la operación de actualización.
Para especificar cómo se comporta la restricción de FOREING KEY cada vez
que se elimina o actualiza la PRIMARY KEY, utilice la acción ON DELETE o
ON UPDATE .
Generalmente se soportan las siguientes acciones
• SET NULL, Cuando la clave principal cambia, elimina o actualiza, las
claves secundarias correspondientes de todas las filas en la tabla
secundaria se establecen en NULL.
• SET DEFAULT, La acción SET DEFAULT establece el valor de la clave
externa en el valor predeterminado especificado en la definición de la
columna cuando crea la tabla.
• RESTRICT, La acción RESTRICT no le permite cambiar o eliminar valores
en la clave principal de la tabla principal.
• NO ACTION, La NO ACTION no significa eludir la restricción de clave
externa. Tiene el mismo efecto que RESTRICT.
• CASCADE, La acción CASCADE propaga los cambios de la tabla
principal a la tabla secundaria cuando actualiza o elimina la clave
principal.
En la práctica, los valores de la clave principal en la tabla principal no cambian,
por lo que las reglas de actualización son menos importantes. La regla más
importante es la regla DELETE que especifica la acción cuando se elimina la
clave principal.
5.3. NOT NULL
Cuando crea una tabla, puede especificar si una columna acepta valores NULL
o no. De forma predeterminada, todas las columnas de una tabla aceptan valores
NULL, excepto que utilice explícitamente restricciones NOT NULL.
Para definir una restricción NOT NULL para una columna, utilice la siguiente
sintaxis:
CREATE TABLE table_name (
...,
column_name type_name NOT NULL,
6
...
);
A diferencia de otras restricciones como PRIMARY KEY y CHECK, solo puede
definir restricciones NOT NULL a nivel de columna, no a nivel de tabla. Basado
en el estándar SQL, PRIMARY KEY siempre debe implicar NOT NULL.
Una vez que se adjunta una restricción NOT NULL a una columna, cualquier
intento de establecer el valor de la columna en NULL, como insertar o actualizar,
provocará una violación de la restricción.
5.4. UNIQUE
Una restricción UNIQUE garantiza que todos los valores de una columna o un
grupo de columnas sean distintos entre sí o únicos.
Para definir una restricción UNIQUE, utilice la palabra clave UNIQUE seguida de
una o más columnas.
Puede definir una restricción UNIQUE a nivel de columna o de tabla. Solo a nivel
de tabla, puede definir una restricción UNIQUE en varias columnas.
A continuación se muestra cómo definir una restricción UNIQUE para una
columna a nivel de columna:
CREATE TABLE table_name(
...,
column_name type UNIQUE,
...
);
O a nivel de tabla
CREATE TABLE table_name(
...,
UNIQUE(column_name1,column_name2,...)
);
Una vez que se define una restricción UNIQUE, si intenta insertar o actualizar un
valor que ya existe en la columna, se emitirá un error y cancelará la operación.
5.5. CHECK
Las restricciones SQL CHECK le permiten definir expresiones para probar
valores cada vez que se insertan o actualizan dentro de una columna.
Si los valores no cumplen con los criterios definidos por la expresión, SQLite
emitirá una violación de restricción y anulará la declaración.

7
Las restricciones CHECK le permiten definir verificaciones de integridad de datos
adicionales más allá de UNIQUE o NOT NULL para adaptarse a su aplicación
específica.
SQL le permite definir una restricción CHECK a nivel de columna o de tabla.
La siguiente declaración muestra cómo definir una restricción CHECK en el nivel
de columna:
CREATE TABLE table_name(
...,
column_name data_type CHECK(expression),
...
);
A nivel de tabla
CREATE TABLE table_name(
...,
CHECK(expression)
);
En esta sintaxis, cada vez que se inserta una fila en una tabla o se actualiza una
fila existente, la expresión asociada con cada restricción CHECK se evalúa y
devuelve un valor numérico 0 o 1.
Si el resultado es cero, entonces ocurrió una violación de la restricción. Si el
resultado es un valor distinto de cero o NULL, significa que no se produjo ninguna
infracción de restricción.
Tenga en cuenta que la expresión de una restricción CHECK no puede contener
una subconsulta.
5.6. AUTOINCREMENT
Genera un numero entero incremental que suma 1 secuencial partiendo desde 1
ante cada INSERT en la tabla. Se busca que nunca se repita este id como
registro
CREATE TABLE people ( person_id INTEGER PRIMARY KEY
AUTOINCREMENT, first_name text NOT NULL, last_name
text NOT NULL
);

6. VIEWS (VISTAS)
En la teoría de bases de datos, una vista es un conjunto de resultados de una
consulta almacenada. Una vista es la forma de empaquetar una consulta en un
objeto con nombre almacenado en la base de datos.

8
Puede acceder a los datos de las tablas subyacentes a través de una vista. Las
tablas a las que hace referencia la consulta en la definición de vista se
denominan tablas base.
Una vista es útil en algunos casos:
• En primer lugar, las vistas proporcionan una capa de abstracción sobre
las tablas. Puede agregar y quitar columnas en la vista sin tocar el
esquema de las tablas subyacentes.
• En segundo lugar, puede usar vistas para encapsular consultas
complejas con uniones para simplificar el acceso a los datos.
Generalmente las vistas en los motores de base de datos son de solo lectura.
Significa que no puede usar las declaraciones INSERT, DELETE y UPDATE
para actualizar los datos en las tablas base a través de la vista.
Para crear una vista, utilice la declaración CREATE VIEW de la siguiente
manera:
CREATE [TEMP] VIEW [IF NOT EXISTS] view_name[(column-
name-list)] AS
select-statement;
Primero, especifique un nombre para la vista. La opción IF NOT EXISTS solo
crea una nueva vista si no existe. Si la vista ya existe, no hace nada.
En segundo lugar, use la opción TEMP si desea que la vista solo sea visible en
la conexión de base de datos actual. La vista se denomina vista temporal y SQL
elimina automáticamente la vista temporal cada vez que se cierra la conexión a
la base de datos.
En tercer lugar, especifique una instrucción SELECT para la vista. De forma
predeterminada, las columnas de la vista se derivan del conjunto de resultados
de la instrucción SELECT. Sin embargo, puede asignar los nombres de las
columnas de vista que son diferentes del nombre de columna de la tabla.
6.1. DROP VIEW
La instrucción DROP VIEW elimina una vista del esquema de la base de datos.
Esta es la sintaxis básica de la sentencia DROP VIEW:
DROP VIEW [IF EXISTS]
[schema_name.]view_name; En esta sintaxis:
• Primero, especifique el nombre de la vista que desea eliminar después
de las palabras clave DROP VIEW.
• En segundo lugar, especifique el esquema de la vista que desea eliminar.
• En tercer lugar, use la opción IF EXISTS para eliminar una vista solo si
existe. Si la vista no existe, la declaración DROP VIEW IF EXISTS no
hace nada. Sin embargo, si intenta descartar una vista que no existe sin
la opción SI EXISTE, se producirá un error.

9
Tenga en cuenta que la declaración DROP VIEW solo elimina el objeto de vista
del esquema de la base de datos. No elimina los datos de las tablas base.

7. INDEX (INDICES)
En las bases de datos relacionales, una tabla es una lista de filas. Al mismo
tiempo, cada fila tiene la misma estructura de columna que consta de celdas.
Cada fila también tiene un número de secuencia de ID de fila consecutivo que
se usa para identificar la fila. Por lo tanto, puede considerar una tabla como una
lista de pares: (rowid, row).
A diferencia de una tabla, un índice tiene una relación opuesta: (row, rowid). Un
índice es una estructura de datos adicional que ayuda a mejorar el rendimiento
de una consulta.

Los motores de BD suelen usar B-tree para organizar índices. Tenga en cuenta
que B significa equilibrado, B-tree es un árbol equilibrado (balanced), no un árbol
binario.
El árbol B mantiene equilibrada la cantidad de datos en ambos lados del árbol,
de modo que el número de niveles que deben atravesarse para ubicar una fila
sea siempre el mismo número aproximado. Además, las consultas con igualdad
(=) y rangos (>, >=, <,<=) en los índices del árbol B son muy eficientes. cómo
funciona un índice?
Cada índice debe estar asociado a una tabla específica. Un índice consta de
una o más columnas, pero todas las columnas de un índice deben estar en la
misma tabla. Una tabla puede tener múltiples índices.

Cada vez que crea un índice, se crea una estructura de árbol B para contener
los datos del índice.
El índice contiene datos de las columnas que especifica en el índice y el valor
de ID de fila correspondiente. Esto ayuda a ubicar rápidamente la fila en función
de los valores de las columnas indexadas.

10
Imagine un índice en la base de datos como el índice de un libro. Al mirar el
índice, puede identificar rápidamente los números de página en función de las
palabras clave.
7.1. CREATE INDEX
Para crear un índice, utilice la instrucción CREATE INDEX con la siguiente
sintaxis:
CREATE [UNIQUE] INDEX index_name
ON table_name(column_list);
Para crear un índice, especifica tres datos importantes:
• El nombre del índice después de las palabras clave CREATE
INDEX.
• El nombre de la tabla al que pertenece el índice. Una lista de
columnas del índice.
En caso de que desee asegurarse de que los valores en una o más columnas
sean únicos, como el correo electrónico y el teléfono, use la opción UNIQUE en
la instrucción CREATE INDEX. El CREATE INDEX UNIQUE crea un nuevo
índice único.
Para verificar si SQL usa el índice o no, use la instrucción EXPLAIN QUERY
PLAN de la siguiente manera:
EXPLAIN QUERY PLAN
SELECT
field FROM table WHERE
condition;
El resultado será un registro de este estilo:

7.2. INDICES MULTICOLUMNA


Si crea un índice que consta de una columna, SQL usa esa columna como clave
de ordenación. En caso de que cree un índice que tenga varias columnas, SQL
usa las columnas adicionales como la segunda, tercera,... como claves de
ordenación.
SQL ordena los datos en el índice de varias columnas por la primera columna
especificada en la instrucción CREATE INDEX. Luego, ordena los valores
duplicados por la segunda columna, y así sucesivamente.
Por lo tanto, el orden de las columnas es muy importante cuando crea un índice
de varias columnas.
Para utilizar un índice de varias columnas, la consulta debe contener la
condición que tiene el mismo orden de columnas definido en el índice.

11
CREATE INDEX index_name
ON table (field1, field2);
DROP INDEX
Para eliminar un índice de una base de datos, utilice la declaración DROP
INDEX de la siguiente manera:
DROP INDEX [IF EXISTS] index_name;
En esta sintaxis, especifica el nombre del índice que desea eliminar después de
las palabras clave DROP INDEX. La opción IF EXISTS elimina un índice solo si
existe.
7.3. INDICE BASADO EN EXPRESIONES
Cuando crea un índice, a menudo usa una o más columnas en una tabla.
Además de los índices normales, se permite formar un índice basado en las
expresiones de las columnas de la tabla. Este tipo de índice se denomina índice
basado en expresiones.
La siguiente consulta selecciona los clientes cuya longitud de la empresa es
mayor a 10 caracteres.
SELECT customerid, company
FROM customers
WHERE length(company) > 10
ORDER BY length(company) DESC;
Si usa la declaración EXPLAIN QUERY PLAN, encontrará que el planificador de
consultas de SQL tuvo que escanear toda la tabla de clientes para devolver el
conjunto de resultados.
Para crear un índice basado en la expresión LENGTH(company), utilice la
siguiente instrucción.
CREATE INDEX customers_length_company
ON customers(LENGTH(company));
Ahora, si ejecuta la consulta anterior nuevamente, se usará el índice de
expresión para buscar y seleccionar los datos, lo cual es más rápido.
A continuación se enumeran todas las restricciones sobre la expresión que
aparece en la instrucción CREATE INDEX.
• La expresión debe hacer referencia únicamente a las columnas de la
tabla que se está indexando. No puede hacer referencia a las columnas
de otras tablas.
• La expresión solo puede usar la llamada de función determinista.
• La expresión no puede utilizar una subconsulta.

12
8. TRIGGERS (DISPARADORES/ACTIVADORES)
Un trigger es un objeto de base de datos con nombre que se ejecuta
automáticamente cuando se emite una instrucción INSERT, UPDATE o DELETE
en la tabla asociada.
¿Cuándo necesitamos un trigger?
A menudo se utiliza trigger para habilitar auditorías sofisticadas. Por ejemplo,
desea registrar los cambios en los datos confidenciales, como el salario y la
dirección, cada vez que cambie.
Además, se utiliza trigger para aplicar reglas comerciales complejas de forma
centralizada en el nivel de la base de datos y evitar transacciones no válidas.
8.1. CREATE TRIGGER
Para crear un nuevo trigger, utilice la declaración CREATE TRIGGER de la
siguiente manera:
CREATE TRIGGER [IF NOT EXISTS] trigger_name
[BEFORE|AFTER|INSTEAD OF] [INSERT|UPDATE|DELETE]
ON table_name
[WHEN condition]
BEGIN
statements;
END;
Primero, especifique el nombre del trigger después de las palabras clave
CREATE TRIGGER.
A continuación, determine cuándo se dispara el trigger, como BEFORE, AFTER
o INSTEAD OF. Puede crear trigger BEFORE y AFTER en una tabla. Sin
embargo, solo puede crear un trigger INSTEAD OF en una vista.
Luego, especifique el evento que hace que se invoque el trigger, como INSERT,
UPDATE o DELETE.
Después de eso, indique la tabla a la que pertenece el trigger.
Finalmente, coloque la lógica de trigger en el bloque BEGIN END, que puede
ser cualquier instrucción SQL válida.
Si combina el momento en que se dispara el trigger y el evento que hace que se
dispare el trigger, tiene un total de 9 posibilidades:
• BEFORE INSERT
• AFTER INSERT
• BEFORE UPDATE
• AFTER UPDATE

13
• BEFORE DELETE
• AFTER DELETE
• INSTEAD OF INSERT
• INSTEAD OF DELETE
• INSTEAD OF UPDATE
Suponga que usa una instrucción UPDATE para actualizar 10 filas en una tabla,
el trigger asociado con la tabla se activa 10 veces. Este trigger se llama trigger
FOR EACH ROW. Si el trigger asociado con la tabla se dispara una vez,
llamamos a este trigger un trigger FOR EACH STATEMENT.
Si usa una condición en la cláusula WHEN, el trigger solo se invoca cuando la
condición es verdadera. En caso de que omita la cláusula WHEN, el trigger se
ejecuta para todas las filas.
Tenga en cuenta que si elimina una tabla, también se eliminan todos los triggeres
asociados. Sin embargo, si el trigger hace referencia a otras tablas, el trigger no
se elimina ni cambia si se eliminan o actualizan otras tablas.
Por ejemplo, si un trigger hace referencia a una tabla llamada personas, quita la
tabla de personas o le cambia el nombre, necesita cambiar manualmente la
definición del trigger.
Puede acceder a los datos de la fila que se está insertando, eliminando o
actualizando usando las referencias OLD y NEW en la forma:
OLD.nombre_columna y NEW.nombre_columna. Las referencias OLD y NEW
están disponibles según el evento que provoca que se dispare el trigger.

La siguiente tabla ilustra las reglas.:

Action Reference
INSERT NEW esta disponible
UPDATE NEW y OLD estan disponibles
DELETE OLD esta disponible
8.2. DROP TRIGGER
Para descartar un disparador existente, use la declaración DROP TRIGGER de
la siguiente manera:
DROP TRIGGER [IF EXISTS] trigger_name; En
esta sintaxis:

Primero, especifique el nombre del trigger que desea eliminar después


de las palabras clave DROP TRIGGER.

14
En segundo lugar, use la opción IF EXISTS para eliminar el trigger solo si
existe.
Tenga en cuenta que si elimina una tabla, SQL descartará automáticamente
todos los trigger asociados con la tabla.
INSTEAD OF
En SQL, un activador INSTEAD OF solo se puede crear en función de una vista,
no de una tabla.
Las vistas son de solo lectura. Y si emite una instrucción DML como INSERT,
UPDATE o DELETE contra una vista, recibirá un error.
Cuando una vista tiene un trigger INSTEAD OF, el trigger se activará cuando
emita una instrucción DML correspondiente. Esto le permite inyectar su propia
lógica en el flujo de procesamiento.
Por ejemplo, si una vista tiene un trigger INSTEAD OF INSERT, cuando emita
una instrucción INSERT, el trigger se activará automáticamente. Dentro del
trigger, puede insertar, actualizar o eliminar datos en las tablas base.
En otras palabras, los trigger INSTEAD OF permiten que las vistas se vuelvan
modificables.
A continuación, se ilustra la sintaxis de crear un activador INSTEAD OF en
SQLite:
CREATE TRIGGER [IF NOT EXISTS] schema_ame.trigger_name
INSTEAD OF [DELETE | INSERT | UPDATE OF column_name]
ON table_name
BEGIN
-- insert code here
END;
En esta sintaxis:
• Primero, especifique el nombre del trigger después de las palabras clave
CREATE TRIGGER. Use IF NOT EXISTS si desea crear el trigger solo si
existe.
• En segundo lugar, use las palabras clave INSTEAD OF seguidas de un
evento desencadenante como INSERTAR, ACTUALIZAR o ELIMINAR.
En tercer lugar, especifique el nombre de la vista a la que pertenece el
trigger.
Finalmente, especifique el código que ejecuta la lógica.

15
1. DJANGO
Django es un framework de desarrollo web de alto nivel y de código abierto
escrito en Python. Fue creado originalmente por Adrian Holovaty y Simon
Willison y lanzado en 2005. Django sigue el principio del diseño MVC (Modelo-
Vista-Controlador) y tiene como objetivo principal ayudarte a construir
aplicaciones web de manera rápida y eficiente.
Ventajas:
• Productividad: Django está diseñado para mejorar la productividad de
los desarrolladores. Proporciona una gran cantidad de funcionalidades
listas para usar, como autenticación de usuarios, manejo de formularios,
administración de bases de datos, generación de URLs y más. Estas
características preconstruidas permiten desarrollar aplicaciones web de
forma más rápida y eficiente.
• Escalabilidad: Django está diseñado para manejar aplicaciones web de
cualquier tamaño. Puede escalar desde pequeñas aplicaciones hasta
proyectos grandes y complejos. Django proporciona herramientas para
ayudar en el escalado de aplicaciones y manejo de tráfico, como la
posibilidad de dividir la carga de trabajo en servidores diferentes o usar
cachés para mejorar el rendimiento.
• Seguridad: Django tiene una sólida política de seguridad. Proporciona
herramientas para prevenir ataques comunes, como inyecciones SQL,
ataques de scripting entre sitios (XSS) y ataques de falsificación de
solicitudes entre sitios (CSRF). Django también facilita el almacenamiento
seguro de contraseñas y manejo de permisos de usuarios.
• Versatilidad: Django es muy versátil y se puede utilizar para desarrollar
una amplia gama de aplicaciones web. Es adecuado tanto para sitios web
pequeños y sencillos como para aplicaciones web empresariales
complejas. Además, Django es compatible con una variedad de bases de
datos, incluyendo PostgreSQL, MySQL y SQLite.

En cuanto a la popularidad, Django es uno de los frameworks web más populares


en el mundo de Python. Tiene una gran comunidad de desarrolladores activos
que contribuyen a su desarrollo y proporcionan soporte en foros y listas de
correo. Además, muchas empresas y organizaciones reconocidas utilizan
Django para desarrollar sus aplicaciones web.
Los sitios de alto nivel que usan Django incluyen: Disqus, Instagram, Knight
Foundation,MacArthur Foundation, Mozilla, National Geographic, Open
Knowledge Foundation,Pinterest y Open Stack. Continua sacando versiones y
tiene planificados lanzamientos hasta 2026-

1
2. FUNCIONAMIENTO
En un sitio web tradicional basado en datos, una aplicación web espera
peticiones HTTP del explorador web (o de otro cliente). Cuando se recibe una
petición la aplicación elabora lo que se necesita basándose en la URL y
posiblemente en la información incluida en los datos POST o GET.
Dependiendo de qué se necesita quizás pueda entonces leer o escribir
información desde una base de datos o realizar otras tareas requeridas para
satisfacer la petición.
La aplicación devolverá a continuación una respuesta al explorador web, con
frecuencia creando dinámicamente una página HTML para que el explorador la
presente insertando los datos recuperados en marcadores de posición dentro de
una plantilla HTML.
Las aplicaciones web de Django normalmente agrupan el código que gestiona
cada uno de estos pasos en archivos separados.

3. CONCEPTOS PRINCIPALES
Modelo: Los modelos en Django son clases que representan las tablas de la
base de datos. Los modelos definen los campos y comportamientos de los datos.
Django proporciona una capa de abstracción para interactuar con la base de
datos, lo que facilita la creación, consulta, actualización y eliminación de
registros.
Vista: Las vistas en Django son funciones o clases que procesan las solicitudes
de los usuarios y devuelven una respuesta. Las vistas se encargan de extraer
los datos necesarios de los modelos y enviarlos a una plantilla para su
presentación al usuario.

2
Plantilla: Las plantillas en Django son archivos que definen cómo se mostrará la
información al usuario final. Las plantillas permiten mezclar contenido estático y
dinámico, y utilizan etiquetas y filtros para manipular y presentar los datos.
URLconf: La URLconf en Django es un mapeo entre las URL entrantes y las
vistas correspondientes que manejarán esas URL. La URLconf determina qué
vista se debe llamar según la URL solicitada.
Formularios: Los formularios HTML se usan para recolectar datos de los
usuarios para su procesamiento en el servidor. Django simplifica la creación,
validación y procesamiento de los formularios.
Autenticación y permisos de los usuarios: Django incluye un sistema robusto
de autenticación y permisos que ha sido construido con la seguridad en mente.
Cacheo: La creación dinámica de contenido es mucho más intensiva
computacionalmente que un servicio de contenido estático. Django proporciona
un cacheo flexible de forma que puedes almacenar todo o parte de una página
renderizada para que no sea re-renderizada nada más que cuando sea
necesario.
Sitio de Administración: el sitio de administración de Django está incluido por
defecto cuando creas una app usando el esqueleto básico. Esto hace que sea
trivialmente fácil proporcionar una página de administración para que los
administradores puedan crear ,editar y visualizar cualquiera de los modelos de
datos de su sitio.
Serialización de datos: Django hace fácil el serializar y servir tus datos como
XML o JSON. Esto puede ser útil cuando se está creando un servicio web (un
sitio web que sólo sirve datos para ser consumidos por otras aplicaciones o sitios,
y que no presenta en pantalla nada por sí mismo), o cuando se crea un sitio web
en el que el código del lado cliente maneja toda la renderización de los datos
4. INSTALACIÓN DJANGO
4.1. ENTORNO DESARROLLO
El entorno de desarrollo es una instalación de Django en tu computadora para
que puedes usar, desarrollar y probar apps Django antes de desplegarlas al
entorno de producción.
Las principales herramientas que el mismo Django proporciona son un conjunto
de scripts de Python para crear y trabajar con proyectos Django, junto con un
simple servidor web de desarrollo que puedes usar para probar de forma local
(es decir en tu computadora, no en un servidor web externo) aplicaciones web
Django con el explorador web de tu computadora.
Hay otras herramientas periféricas que venimos utilizando desde el principio del
curso, que forman parte del entorno de desarrollo, como por ejemplo Visual
Code(IDE).
Django es extremadamente flexible en términos de cómo y dónde puede
instalarse y configurarse. Django puede ser:instalado en diferentes sistemas

3
operativos, ser usado con Python 3 y Python 2, instalado desde las fuentes,
desde el Python Package Index (PyPi) y en muchos casos desde la aplicación
de gestión de paquetes de la computadora, configurado para usar una de entre
varias bases de datos, que pueden también necesitar ser instaladas y
configuradas por separado, ejecutarse en el entorno Python del sistema principal
o dentro de entornos virtuales Python separados.
Nosotros vamos a poner el foco en la instalación en Windows y utilizando
entornos virtuales separados.
4.2. ENTORNO VIRTUAL
Cuando instalas Python3 obtienes un único entorno global que es compartido
con todo el código Python3. Si bien puedes instalar los paquetes que te gusten
en el entorno, sólo puedes instalar al mismo tiempo una versión en particular de
cada paquete.
Si instalas Django dentro del entorno por global sólo podrás apuntar a una sola
versión de Django en la computadora. Esto puede ser un problema si quieres
crear nuevos sitios(usando la última versión de Django) pero manteniendo los
sitios web que dependen de versiones más antiguas.
Como resultado, los desarrolladores experimentados de Python/Django
normalmente ejecutan las aplicaciones Python dentro de entornos virtuales
Python independientes. De esta forma se habilitan múltiples entornos Django
diferentes en la misma computadora
Instalar virtualenvwrapper-win es incluso más simple que poner en marcha
virtualenvwrapper porque no necesitas configurar donde almacena la
herramienta la información del entorno (hay un valor por defecto). Todo lo que
necesitas hacer es ejecutar el siguiente comando en la consola de comandos en
línea:
pip3 install virtualenvwrapper-wi
Una vez que hayas instalado virtualenvwrapper o virtualenvwrapper-win trabajar
conentornos virtuales es muy similar en todas las plataformas.
Ahora puedes crear un nuevo entorno virtual con el comando mkvirtualenv. A
medida que se ejecuta este comando verás que se va poniendo en marcha el
entorno.
Cuando se completa el comando el nuevo entorno virtual estará activo — podrás
comprobarlo porque el comienzo del prompt será el nombre del entorno entre
paréntesis.
Hay otros comandos útiles para trabajar en entornos virtuales:
• deactivate — Salir del entorno virutal Python actual
• workon — Listar los entornos virtuales disponibles
• workon name_of_environment — Activar el entorno virtual Python
especificado

4
• rmvirtualenv name_of_environment — Borrar el entorno
especificado.

4.3. INSTALACION
Una vez que has creado el entorno virtual, y realizado la llamada workon para
entrar en él, podés usar pip3 para instalar Django.
pip3 install django
Podés comprobar que está instalado Django ejecutando el siguiente comando
(esto sólo comprueba que Python puede encontrar el módulo Django):
py -3 -m django –versión• 1.11.7

Crear un esqueleto de proyecto para ver si funciona.


Para hacer ésto, navega primero en tu consola de comandos/terminal a donde
quieras almacenar tus aplicaciones Django.
Crea una carpeta para la comprobación de tu sitio y navega a ella.
Puedes crear a continuación un nuevo esqueleto de sitio llamado "mytestsite"
usando la herramienta django-admin como se muestra a continuación.
Después de crear el sitio puedes navegar a la carpeta donde encontrarás el script
principal para la gestión de proyectos, llamado manage.py.
django-admin startproject mytestsite
cd mytestsite
Podemos arrancar el servidor web de desarrollo desde esta carpeta usando
manage.py y elcomando runserver,
python3 manage.py runserver
Una vez que tengas funcionando el servidor puedes ver el sitio navegando a la
siguiente URL en tu explorador web local : http://127.0.0.1:8000/. Deberías ver
un sitio parecido a este:

5
5. PROYECTOS
En Django, un proyecto es la estructura principal de tu aplicación web. Un
proyecto de Django puede contener una o más aplicaciones, y cada aplicación
se encarga de una funcionalidad específica.
Crea un proyecto: Abre tu terminal y navega hasta la ubicación donde deseas
crear el proyecto. Luego, ejecuta el siguiente comando para crear un nuevo
proyecto de Django:
django-admin startproject nombre_del_proyecto
Esto creará una carpeta con el nombre del proyecto y la estructura de archivos
inicial.
Navega al directorio del proyecto: Usa el comando cd para moverte al directorio
del proyecto:
cd nombre_del_proyecto
Ejecuta el servidor de desarrollo: Para ver tu proyecto en acción, ejecuta el
siguiente comando:
python manage.py runserver
Esto iniciará el servidor de desarrollo de Django en tu máquina local.
Una vez que hayas creado y ejecutado tu proyecto, puedes comenzar a trabajar
en tus aplicaciones Django.
6. Aplicaciones
En Django, una aplicación es un componente modular y reutilizable que forma
parte de un proyecto. Cada aplicación en Django se encarga de una
funcionalidad específica de la aplicación web en general. Por ejemplo, en un
blog, podrías tener una aplicación para administrar los usuarios, otra para
gestionar los posts y una tercera para manejar los comentarios
Puedes crear una nueva aplicación dentro del proyecto utilizando el siguiente
comando:
python manage.py startapp nombre_de_la_aplicacion

Dentro de una aplicación Django, puedes definir tus modelos, vistas y plantillas
para implementar la lógica y la interfaz de tu aplicación web.
Además de estos elementos principales, una aplicación Django también puede
contener otros archivos y directorios opcionales, como archivos de configuración,
archivos estáticos para CSS e imágenes, y archivos de migración para gestionar
los cambios en los modelos y la base de datos.

6
Cada aplicación Django es independiente y puede ser reutilizada en diferentes
proyectos. Esto facilita la modularidad y la reutilización de código, lo que hace
que el desarrollo de aplicaciones web sea más eficiente.
En un proyecto de Django, las aplicaciones se configuran y se ven principalmente
en los siguientes lugares:
Estructura de directorios: Las aplicaciones se encuentran en la estructura de
directorios del proyecto. Cada aplicación tiene su propio directorio, que
generalmente se crea utilizando el comando startapp de Django. Estos
directorios de aplicaciones se encuentran en el mismo nivel que el directorio
principal del proyecto.
Archivo settings.py: En el archivo settings.py del proyecto, se configuran y se
agregan las aplicaciones instaladas. Dentro de este archivo, hay una variable
llamada INSTALLED_APPS, donde debes incluir los nombres de las aplicaciones
que deseas habilitar en tu proyecto. Por ejemplo:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'mi_aplicacion', # Nombre de tu aplicación
]
Al agregar el nombre de tu aplicación en la lista INSTALLED_APPS, Django
reconoce y carga esa aplicación cuando se ejecuta el proyecto.
Archivo urls.py: En el archivo urls.py del proyecto, se definen los patrones de
URL y se mapean a las vistas correspondientes de las aplicaciones. Aquí es
donde puedes especificar las rutas de acceso y las vistas que se deben utilizar
para manejar las solicitudes de URL. Por ejemplo:
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('mi-aplicacion/', include('mi_aplicacion.urls')),
]
7
En este caso, todas las URLs que comiencen con "mi-aplicacion/" se dirigirán a
las URLs definidas en el archivo urls.py de tu aplicación.
7. Vistas
En Django, una vista es una función o una clase que procesa una solicitud HTTP
y devuelve una respuesta al cliente. La vista se encarga de la lógica de negocio
de una página web o de una funcionalidad específica de una aplicación.
En una vista, puedes realizar diversas tareas, como consultar la base de datos,
procesar datos enviados por el usuario, realizar cálculos, y decidir qué plantilla
se utilizará para mostrar los datos.
Las vistas en Django pueden ser implementadas de dos formas:
Funciones de vista: Una vista basada en función es una función de Python que
recibe una solicitud HTTP como argumento y devuelve una respuesta HTTP.
ejemplo:
from django.http import HttpResponse
def saludo(request):
return HttpResponse("¡Hola, bienvenido a mi sitio web!")
Clases de vista: Una vista basada en clase es una clase de Python que hereda
de una clase base proporcionada por Django y define métodos para manejar
diferentes tipos de solicitudes HTTP. Django proporciona clases de vista
predefinidas que cubren la mayoría de los casos de uso comunes. ejemplo:
from django.views import View
from django.http import HttpResponse
class SaludoView(View):
def get(self, request):
return HttpResponse("¡Hola, bienvenido a mi sitio
web!")
Es importante tener en cuenta que una vista en Django no se ocupa directamente
de generar HTML. En su lugar, una vista generalmente interactúa con los
modelos, recupera datos necesarios, realiza procesamientos y luego pasa esos
datos a una plantilla. La plantilla se encargará de la presentación visual y
generará la respuesta HTML final.
Además, las vistas en Django pueden utilizar el sistema de enrutamiento de URL
para determinar qué vista debe manejar una solicitud en función de la URL
solicitada. El archivo urls.py en tu proyecto define cómo se mapean las URL a
las vistas correspondientes.
8. Templates

8
En Django, un template es un archivo que define la estructura y el diseño de una
página web. Los templates permiten separar la lógica de presentación de la
lógica de negocio de una aplicación web, lo que facilita el desarrollo y
mantenimiento del código.
Un template en Django utiliza la sintaxis del lenguaje de plantillas de Django
(Django Template Language o DTL). Esta sintaxis es similar a HTML pero agrega
características adicionales y permite la incorporación de lógica de plantillas.
Ejemplo de un template en Django:
<!DOCTYPE html>
<html>
<head>
<title>Mi Sitio Web</title>
</head>
<body>
<h1>{{ titulo }}</h1>

<ul>
{% for item in lista %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>
En este ejemplo, el template muestra un título y una lista de elementos. Observa
que hay secciones especiales del template delimitadas por {% %} y {{ }}.
{% for item in lista %} y {% endfor %} son etiquetas de control de flujo que
permiten iterar sobre una lista y mostrar elementos repetitivos.
{{ titulo }} y {{ item }} son variables del template que se reemplazarán con valores
dinámicos cuando el template se renderice.
Para utilizar un template en Django, debes seguir estos pasos:
Crear un archivo de template: Crea un archivo con extensión .html o .txt
(dependiendo del tipo de contenido) en un directorio designado para almacenar
los templates. Por convención, este directorio se llama "templates" y debe estar
dentro de la aplicación.

9
Escribir el código HTML y DTL: En el archivo de template, escribe el código
HTML y utiliza las etiquetas y variables de DTL para controlar la lógica y la
presentación del template.
Renderizar el template desde una vista: En una vista de Django, importa la
función render y utiliza esta función para renderizar el template. Puedes pasarle
los datos necesarios como contexto para reemplazar las variables del template.
Ejemplo:
from django.shortcuts import render

def my_view(request):
titulo = "Mi Sitio Web"
lista = ["Elemento 1", "Elemento 2", "Elemento 3"]
context = {
'titulo': titulo,
'lista': lista
}
return render(request, 'template.html', context)
En este ejemplo, la función render toma la solicitud (request), el nombre del
archivo de template (template.html) y un diccionario de contexto (context) que
contiene los valores de las variables del template.
Configurar la ruta en el archivo urls.py: Asegúrate de tener una ruta
configurada en el archivo urls.py de tu proyecto que vincule una URL con la vista
correspondiente. Esta vista será la encargada de renderizar el template.
Una vez que hayas seguido estos pasos, Django tomará el template,
reemplazará las variables y las etiquetas de control de flujo con los valores
correctos y generará una respuesta HTML que será enviada al cliente.
9. Herencias de Templates
En Django, la herencia de templates es una poderosa característica que permite
definir un template base o padre y luego extenderlo o personalizarlo en templates
hijos. Esto promueve la reutilización de código y la organización estructurada de
los templates.
La herencia de templates en Django se logra utilizando bloques (blocks) y la
directiva {% extends %}. Ejemplo:

Template base (base.html):

10
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Título por defecto{% endblock
%}</title>
</head>
<body>
<header>
{% block header %}
<h1>Mi Sitio Web</h1>
{% endblock %}
</header>

<div class="content">
{% block content %}
<p>Contenido del sitio</p>
{% endblock %}
</div>

<footer>
{% block footer %}
<p>Pie de página</p>
{% endblock %}
</footer>
</body>
</html>
Template hijo (child.html):
{% extends 'base.html' %}

{% block title %}Título personalizado{% endblock %}

11
{% block content %}
<p>Contenido personalizado</p>
<p>Más contenido personalizado</p>
{% endblock %}
En este ejemplo, el template base (base.html) define la estructura HTML básica
y proporciona bloques (blocks) donde los templates hijos pueden agregar su
propio contenido.
El template hijo (child.html) extiende el template base utilizando la directiva
{% extends 'base.html' %}. Esto indica que el template hijo hereda todo
el contenido y la estructura del template base.
Luego, en el template hijo, se pueden personalizar los bloques heredados
utilizando las etiquetas {% block %}. Por ejemplo, se redefine el bloque title
para establecer un título personalizado y se redefine el bloque content para
agregar contenido adicional.
Cuando se renderiza el template hijo, Django combina el contenido del template
base y el template hijo, reemplazando los bloques definidos en el template hijo
dentro del template base. El resultado final es una página web que utiliza la
estructura y el contenido del template base, pero con las personalizaciones
específicas del template hijo.
La herencia de templates en Django permite crear una jerarquía de templates,
donde puedes tener múltiples niveles de herencia, lo que te brinda flexibilidad
para organizar y personalizar tus templates de manera modular.

12
1- RECURSOS ESTATICOS
Los recursos estáticos en Django son archivos como imágenes, hojas de estilo
CSS, archivos JavaScript y otros archivos estáticos que se utilizan para definir la
apariencia y la funcionalidad de una aplicación web. Estos archivos no cambian
dinámicamente y se sirven directamente al navegador.
Para incorporar recursos estáticos en un proyecto Django, sigue estos pasos:
Crear una carpeta para los archivos estáticos: En la raíz del proyecto Django,
crea una carpeta llamada "static" si aún no existe. Dentro de esta carpeta,
puedes crear subcarpetas para organizar los diferentes tipos de archivos
estáticos, como "static/css" para las hojas de estilo y "static/js" para los archivos
JavaScript.
Configurar la configuración de archivos estáticos: En el archivo de
configuración settings.py de tu proyecto Django, asegúrate de tener la
configuración adecuada para los archivos estáticos. Verifica que la variable
STATIC_URL esté definida y que apunte a la URL de los archivos estáticos. Por
ejemplo, puedes establecer STATIC_URL = '/static/'.
Referenciar los archivos estáticos en los templates: En tus templates HTML,
puedes utilizar la etiqueta {% load static %} al comienzo del archivo para cargar
la funcionalidad de archivos estáticos. Luego, puedes hacer referencia a los
archivos estáticos utilizando la sintaxis {% static 'ruta/al/archivo' %}. Por ejemplo,
para incluir un archivo CSS, puedes usar <link rel="stylesheet" href="{% static
'css/estilos.css' %}">.
Ejemplo:
En la raíz del proyecto Django, crea una carpeta llamada "static" si aún no existe.
Dentro de la carpeta "static", crea una subcarpeta llamada "css" para las hojas
de estilo.
En el archivo settings.py de tu proyecto Django, asegúrate de tener la
configuración adecuada para los archivos estáticos:
STATIC_URL = '/static/'
Dentro de la carpeta "css", crea un archivo llamado "estilos.css" con el siguiente
contenido:
/* estilos.css */
body {
background-color: #f2f2f2;
}

h1 {
color: #333;
1
}

En tu template HTML, asegúrate de tener la etiqueta {% load static %} al


comienzo del archivo para cargar la funcionalidad de archivos estáticos. Luego,
puedes hacer referencia a los archivos estáticos utilizando la sintaxis {% static
'ruta/al/archivo' %}. Por ejemplo:
<!DOCTYPE html>
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'css/estilos.css'
%}">
</head>
<body>
<h1>Bienvenido a mi sitio web</h1>
</body>
</html>

En este ejemplo, se carga el archivo "estilos.css" utilizando la etiqueta {% static


'css/estilos.css' %}. Cuando el template se renderice, Django reemplazará esa
etiqueta por la URL correcta del archivo estático.
Asegúrate de que la estructura de carpetas y los nombres de archivos coincidan
con los ejemplos proporcionados. Además, verifica que la configuración
STATIC_URL esté correctamente definida en settings.py.
2- ORM
Un ORM (Object-Relational Mapping) es una técnica que permite mapear objetos
de un lenguaje de programación orientado a objetos a estructuras de datos
relacionales en una base de datos. Su objetivo principal es facilitar la interacción
y manipulación de datos en una base de datos utilizando objetos y consultas
orientadas a objetos en lugar de consultas SQL tradicionales.
Django se comporta como un ORM al proporcionar su propio mapeo objeto-
relacional. Utiliza una capa de abstracción de base de datos que permite a los
desarrolladores interactuar con la base de datos utilizando objetos de Python en
lugar de escribir consultas SQL directamente. Algunas características clave de
cómo Django se comporta como un ORM son:
Modelos: En Django, los modelos son clases de Python que definen la estructura
y el comportamiento de los datos en la base de datos. Cada modelo representa
una tabla en la base de datos y cada atributo del modelo representa una columna
de la tabla. Los modelos también pueden definir relaciones entre ellos, como
claves primarias y foráneas.
2
Consultas: Django proporciona una API de consultas que permite realizar
consultas a la base de datos utilizando métodos de Python encadenados. Estos
métodos son intuitivos y expresivos, lo que facilita la realización de consultas
complejas. La API de consultas de Django se encarga de traducir las consultas
de alto nivel en SQL y ejecutarlas en la base de datos subyacente.
Migraciones: Django incluye un sistema de migraciones que permite realizar
cambios en la estructura de la base de datos de manera incremental y
controlada. Las migraciones se definen como archivos de Python y se encargan
de aplicar los cambios en la base de datos, como agregar tablas, modificar
columnas o crear índices.
Abstracción de base de datos: Django proporciona una capa de abstracción
de base de datos que permite escribir código independiente de la base de datos
subyacente. Esto significa que puedes desarrollar una aplicación Django
utilizando una base de datos relacional como MySQL y luego cambiar a otra base
de datos relacional como PostgreSQL sin tener que modificar tu código.
3- MODELOS
En Django, un modelo es una clase de Python que define la estructura y el
comportamiento de los datos en una base de datos. Cada modelo representa
una tabla en la base de datos y cada atributo del modelo representa una columna
de esa tabla. Los modelos en Django se definen utilizando la clase models.Model
como base y se configuran mediante campos que representan las columnas de
la tabla.
Ejemplo:
from django.db import models

class Producto(models.Model):
nombre = models.CharField(max_length=100)
precio = models.DecimalField(max_digits=8,
decimal_places=2)
descripcion = models.TextField()
fecha_creacion =
models.DateTimeField(auto_now_add=True)

def __str__(self):
return self.nombre
En este ejemplo, se define un modelo llamado Producto que representa una tabla
de productos en la base de datos. El modelo tiene cuatro campos: nombre,
3
precio, descripcion y fecha_creacion. Cada campo se define utilizando una clase
de campo proporcionada por Django, como CharField para campos de texto
corto, DecimalField para campos numéricos con decimales y DateTimeField para
campos de fecha y hora.
El método __str__() se utiliza para representar el objeto Producto como una
cadena legible en lugar de mostrar su identificador interno. En este caso,
devuelve el nombre del producto.
Una vez que el modelo está definido, puedes utilizarlo para interactuar con los
datos en la base de datos. Algunos ejemplos de uso comunes incluyen:
Crear un nuevo objeto Producto:
producto = Producto(nombre='Camiseta', precio=29.99,
descripcion='Camiseta de algodón')
producto.save()
Obtener todos los objetos Producto:
productos = Producto.objects.all()

Filtrar los objetos Producto por algún criterio:


productos_baratos = Producto.objects.filter(precio__lt=50)

Actualizar un objeto Producto:


producto = Producto.objects.get(nombre='Camiseta')
producto.precio = 39.99
producto.save()
Eliminar un objeto Producto:
producto = Producto.objects.get(nombre='Camiseta')
producto.delete()

Los modelos proporcionan muchas más funcionalidades, como relaciones entre


modelos, validaciones de datos y métodos personalizados. Los modelos en
Django facilitan la interacción con la base de datos y la manipulación de los datos
en tu aplicación web.
4- PANEL DE ADMINISTRACIÓN
El panel de administración de Django es una interfaz preconstruida que
proporciona una forma fácil de administrar los datos de tu aplicación web. Se
genera automáticamente a partir de los modelos definidos en tu proyecto Django
y ofrece una variedad de funcionalidades para realizar tareas administrativas
comunes, como agregar, editar y eliminar registros de la base de datos.

4
Las principales funcionalidades del panel de administración de Django incluyen:
• CRUD (Crear, Leer, Actualizar, Eliminar): El panel de administración
permite realizar las operaciones básicas de crear, leer, actualizar y
eliminar registros de la base de datos de manera intuitiva. Puedes agregar
nuevos registros, ver una lista de registros existentes, editar los valores
de los campos y eliminar registros.

• Personalización del panel: Puedes personalizar el aspecto y el


comportamiento del panel de administración para que se adapte a tus
necesidades. Puedes personalizar las etiquetas de los campos, los
nombres de los modelos, el diseño de la página, entre otros aspectos.

• Búsqueda y filtrado: El panel de administración ofrece la capacidad de


buscar registros y filtrarlos en función de ciertos criterios. Esto facilita la
navegación y recuperación de datos específicos dentro de la base de
datos.

• Relaciones entre modelos: Si tus modelos tienen relaciones, como claves


foráneas, el panel de administración de Django ofrece funcionalidades
para manejar esas relaciones. Puedes agregar y editar objetos
relacionados directamente desde la interfaz del panel de administración.

• Permisos y autenticación: El panel de administración de Django permite


configurar permisos de acceso y autenticación para los usuarios. Puedes
definir qué usuarios tienen acceso al panel de administración y qué
acciones pueden realizar.

Para usar el panel de administración de Django, sigue estos pasos:


Asegúrate de que el panel de administración esté habilitado en tu proyecto
Django. Verifica que la configuración django.contrib.admin esté incluida en la
lista INSTALLED_APPS en tu archivo settings.py.
Crea un superusuario ejecutando el comando python manage.py
createsuperuser en la terminal. Proporciona un nombre de usuario, una dirección
de correo electrónico y una contraseña para el superusuario.
Ejecuta tu servidor de desarrollo Django utilizando el comando python
manage.py runserver.

5
Accede al panel de administración en tu navegador web. Por defecto, la URL
será http://localhost:8000/admin. Inicia sesión utilizando las credenciales del
superusuario que creaste.
Una vez que hayas iniciado sesión en el panel de administración, podrás ver una
lista de los modelos registrados en tu proyecto Django. Puedes hacer clic en
cualquier modelo para ver y administrar los registros asociados. Por ejemplo, si
tienes un modelo Producto, podrás ver una lista de productos existentes y podrás
agregar, editar o eliminar productos desde el panel de administración.
Además, puedes personalizar aún más el panel de administración definiendo
clases de administración personalizadas para tus modelos. Esto te permite
controlar cómo se muestran y se manejan los modelos en el panel de
administración.
El panel de administración de Django es una herramienta poderosa que te
permite administrar fácilmente los datos de tu aplicación sin tener que escribir
código adicional. Es una característica muy útil para tareas administrativas y de
gestión de contenido en tu proyecto Django
5- MVC
El patrón MVC (Modelo-Vista-Controlador) es un patrón arquitectónico utilizado
en el desarrollo de aplicaciones web para separar las preocupaciones y organizar
el código de manera estructurada. Django sigue este patrón y proporciona una
implementación robusta del mismo. A continuación, te explico brevemente cada
componente del patrón MVC y cómo se refleja en Django:
Modelo (Model): El modelo representa los datos y la lógica de negocio de la
aplicación. En Django, los modelos se definen como clases de Python que
heredan de la clase models.Model. Los modelos definen la estructura de las
tablas de la base de datos y proporcionan métodos para interactuar con los
datos. Django utiliza un ORM (mapeo objeto-relacional) para facilitar la
interacción con la base de datos y realizar consultas.
Vista (View): La vista es responsable de la presentación de los datos y la
interacción con el usuario. En Django, las vistas son funciones o clases de
Python que procesan las solicitudes del usuario y generan las respuestas
correspondientes. Las vistas pueden acceder a los datos del modelo, realizar
cálculos y generar los datos que se muestran al usuario. Las vistas pueden
devolver respuestas en diferentes formatos, como HTML, JSON, XML, etc.
Controlador (Controller): En Django, el controlador es manejado
automáticamente por el framework y se llama "Enrutador de URL" (URL
Dispatcher). El enrutador de URL mapea las URL a las vistas correspondientes
basándose en patrones definidos en el archivo urls.py. El enrutador de URL
determina qué vista se debe ejecutar según la URL solicitada por el usuario.

6
En Django, la estructura de un proyecto típico refleja el patrón MVC. Por ejemplo,
el modelo se define en los archivos models.py de las aplicaciones, las vistas se
definen en los archivos views.py y el enrutador de URL se configura en el archivo
urls.py del proyecto.
Además, Django proporciona otras capas y componentes que complementan el
patrón MVC, como los templates (plantillas) para la presentación de datos y el
ORM para la interacción con la base de datos. El patrón MTV (Modelo-Template-
Vista) es una variante del patrón MVC utilizada en Django, donde el template se
encarga de la presentación y la vista se encarga de la lógica de negocio.
Supongamos que estás construyendo una aplicación web para gestionar una
lista de tareas.:
Modelo (Model): Define la estructura de los datos y la lógica de negocio. En
models.py, podrías tener un modelo Tarea que representa una tarea en la lista.
Por ejemplo:
from django.db import models

class Tarea(models.Model):
titulo = models.CharField(max_length=200)
descripcion = models.TextField()
completada = models.BooleanField(default=False)

def __str__(self):
return self.titulo
Vista (View): Controla la presentación y la interacción con el usuario. En views.py,
puedes definir funciones o clases de vista que procesan las solicitudes y generan
las respuestas. Por ejemplo:
from django.shortcuts import render
from .models import Tarea

def lista_tareas(request):
tareas = Tarea.objects.all()
return render(request, 'tareas/lista_tareas.html',
{'tareas': tareas})

Template (Vista): Se encarga de la presentación de los datos. Puedes crear un


archivo de plantilla lista_tareas.html en el directorio de plantillas de tu aplicación.
Aquí tienes un ejemplo simple:

7
<ul>
{% for tarea in tareas %}
<li>{{ tarea.titulo }}</li>
{% endfor %}
</ul>
En este ejemplo, el bucle {% for %} recorre todas las tareas y muestra el título
de cada una en una lista no ordenada.
Enrutador de URL (Controlador): En urls.py, puedes configurar las URL y
mapearlas a las vistas correspondientes. Por ejemplo:
from django.urls import path
from .views import lista_tareas

urlpatterns = [
path('tareas/', lista_tareas, name='lista_tareas'),
]
En este caso, cuando un usuario accede a /tareas/ en el navegador, se llamará
a la función lista_tareas para procesar la solicitud y mostrar la lista de tareas.

8
1. FORMULARIOS
En Django, un formulario es una representación de una estructura de datos que
permite al usuario interactuar y enviar datos al servidor. Los formularios en
Django proporcionan una forma conveniente de manejar la entrada de datos del
usuario, validarla y procesarla.
Para utilizar un formulario en Django, generalmente se siguen los siguientes
pasos:
Definir un formulario: Se crea una clase que hereda de django.forms.Form o
django.forms.ModelForm, donde se especifican los campos y las validaciones
necesarias.
Renderizar el formulario: Se renderiza el formulario en una plantilla de Django
utilizando las etiquetas y los métodos proporcionados por Django para mostrar
los campos y los mensajes de error si los hubiera.
Procesar los datos enviados: Cuando se envía el formulario, se recibe en una
vista de Django. En esta vista, se valida el formulario y se realiza cualquier
procesamiento adicional necesario, como guardar los datos en la base de datos.
Ejemplo:
from django import forms

class ContactForm(forms.Form):
name = forms.CharField(label='Nombre', max_length=100)
email = forms.EmailField(label='Email', max_length=100)
message = forms.CharField(label='Mensaje',
widget=forms.Textarea)
views.py:
from django.shortcuts import render
from .forms import ContactForm

def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# Procesar los datos del formulario
name = form.cleaned_data['name']

1
email = form.cleaned_data['email']
message = form.cleaned_data['message']
# Realizar cualquier acción adicional (enviar
correo, guardar en la base de datos, etc.)
else:
form = ContactForm()

return render(request, 'contact.html', {'form': form})

contact.html:
<form method="POST" action="{% url 'contact' %}">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Enviar</button>
</form>
En este ejemplo, se define un formulario ContactForm que tiene campos para el
nombre, el correo electrónico y el mensaje. En la vista contact, se muestra el
formulario en la plantilla contact.html. Cuando el formulario se envía, se valida y
se procesan los datos en la misma vista.
En Django, tanto Form como ModelForm son clases que se utilizan para crear y
manejar formularios. Sin embargo, hay una diferencia clave entre ellos:
Form: La clase Form en Django se utiliza para crear formularios independientes
que no están necesariamente vinculados a un modelo específico. Se definen los
campos y las validaciones directamente en la clase del formulario. Es útil cuando
necesitas un formulario personalizado o cuando los datos no se corresponden
directamente con un modelo de base de datos.
ModelForm: La clase ModelForm en Django se utiliza para crear formularios que
están vinculados directamente a un modelo de base de datos. Se basa en un
modelo existente y proporciona campos y validaciones automáticamente según
los campos del modelo. Es útil cuando deseas crear un formulario que coincida
con la estructura y las validaciones del modelo y realizar operaciones CRUD
(Crear, Leer, Actualizar, Eliminar) en la base de datos de manera más sencilla.
Al utilizar un ModelForm, no es necesario definir manualmente los campos y las
validaciones, ya que se generan automáticamente a partir de los campos del
modelo. También proporciona métodos convenientes para guardar o actualizar
los datos del modelo.

Ejemplo:
2
from django import forms
from .models import Producto

# Form
class ContactForm(forms.Form):
name = forms.CharField(label='Nombre', max_length=100)
email = forms.EmailField(label='Email', max_length=100)
message = forms.CharField(label='Mensaje',
widget=forms.Textarea)

# ModelForm
class ProductoForm(forms.ModelForm):
class Meta:
model = Producto
fields = ['nombre', 'precio', 'descripcion']

En el ejemplo anterior, el Form llamado ContactForm se define con campos


personalizados (name, email y message), mientras que el ModelForm llamado
ProductoForm se crea a partir del modelo Producto. El ModelForm hereda
automáticamente los campos y las validaciones del modelo Producto.
En resumen, Form se utiliza para crear formularios independientes, mientras que
ModelForm se utiliza para crear formularios vinculados a modelos de base de
datos existentes, lo que proporciona una forma más rápida y conveniente de
trabajar con los datos del modelo.
2. GET y POST
En HTML, los formularios tienen dos métodos principales para enviar datos al
servidor: POST y GET. En Django, puedes especificar el método que deseas
utilizar en tu formulario a través del atributo method en la etiqueta <form>.
POST: El método POST se utiliza para enviar datos al servidor de forma segura
y no visible en la URL. Los datos enviados a través del método POST se incluyen
en el cuerpo de la solicitud HTTP y no se muestran en la barra de direcciones
del navegador. Esto es útil para enviar información sensible o cuando se envían
datos que modificarán el estado del servidor, como agregar o actualizar datos en
una base de datos. En Django, al procesar un formulario enviado con el método
POST, generalmente se utiliza el decorador @csrf_protect o el middleware csrf
para proteger contra ataques de falsificación de solicitudes entre sitios (CSRF).

3
GET: El método GET se utiliza para enviar datos al servidor a través de la URL.
Los datos se adjuntan a la URL como parámetros de consulta y son visibles en
la barra de direcciones del navegador. El método GET se utiliza comúnmente
para solicitar recursos o recuperar información del servidor, pero no se
recomienda utilizarlo para enviar datos sensibles o que tengan un impacto en el
estado del servidor. En Django, al procesar un formulario enviado con el método
GET, los datos se obtienen del objeto request.GET en la vista.
Ejemplo
<form method="POST" action="{% url 'my_view' %}">
{% csrf_token %}
<!-- Resto de campos del formulario -->
<button type="submit">Enviar</button>
</form>

En este ejemplo, el formulario utiliza el método POST y la etiqueta {% csrf_token


%} se utiliza para agregar un token CSRF requerido por Django para proteger
contra ataques CSRF.
Si prefieres utilizar el método GET, simplemente cambia method="POST" a
method="GET" en la etiqueta <form>. Ten en cuenta que, al utilizar el método
GET, los datos se mostrarán en la URL y podrían ser visibles para los usuarios y
terceros.
En resumen, el método POST se utiliza para enviar datos de forma segura y no
visible, mientras que el método GET se utiliza para enviar datos a través de la
URL. La elección del método depende de la naturaleza de los datos que se están
enviando y las acciones que se realizarán en el servidor.
3. SESIONES
En Django, una sesión se utiliza para almacenar información específica de un
usuario durante su interacción con una aplicación web. Una sesión se crea
cuando un usuario accede a la aplicación y se asocia con una clave única en
forma de cookie o en la URL. Esto permite que la aplicación identifique al usuario
en solicitudes posteriores y recupere los datos almacenados en la sesión.
Django proporciona una interfaz fácil de usar para trabajar con sesiones a través
del objeto request.session.
Habilitar el middleware de sesiones: Asegúrate de que el middleware de
sesiones esté habilitado en la configuración de tu proyecto Django. El
middleware de sesiones es responsable de administrar las sesiones en cada
solicitud y respuesta.
Guardar datos en la sesión: Para guardar datos en la sesión, simplemente
asigna valores a las claves en el objeto request.session. Puedes almacenar

4
cualquier tipo de datos compatible con la serialización de Django, como cadenas,
números, listas o incluso objetos personalizados.
def my_view(request):
# Guardar datos en la sesión
request.session['username'] = 'JohnDoe'
request.session['cart_items'] = ['item1', 'item2',
'item3']

Acceder a los datos de la sesión: Puedes acceder a los datos almacenados


en la sesión en cualquier vista o plantilla mediante el objeto request.session. Los
datos se recuperan utilizando las claves correspondientes.
def another_view(request):
# Acceder a los datos de la sesión
username = request.session['username']
cart_items = request.session.get('cart_items', [])

Eliminar datos de la sesión: Si deseas eliminar un valor específico de la sesión,


puedes utilizar el operador del o el método pop() del objeto request.session.
def logout(request):
# Eliminar datos de la sesión
del request.session['username']
request.session.pop('cart_items', None)
Django se encarga automáticamente de manejar la gestión de las sesiones y la
persistencia de los datos de la sesión, ya sea a través de cookies o mediante
identificadores en la URL. Puedes configurar la forma en que se almacenan y
manejan las sesiones en la configuración de tu proyecto Django.
Es importante tener en cuenta que las sesiones en Django tienen un tiempo de
vida limitado y se pueden configurar para que expiren después de un período de
tiempo específico o cuando el usuario cierre el navegador.
Las sesiones son útiles para mantener información específica de un usuario a lo
largo de su sesión en una aplicación web, como datos de inicio de sesión,
preferencias del usuario o información temporal.
4. AUTENTICACION DE USUARIOS Y PERMISOS
La autenticación de usuarios y los permisos son componentes clave en el
desarrollo de aplicaciones web para garantizar la seguridad y el control de
acceso a diferentes recursos. En Django, existen varias alternativas de
implementación para la autenticación de usuarios y los permisos.

5
Autenticación de usuarios:

Django proporciona un sistema de autenticación completo y robusto llamado


"Authentication Framework". Este marco incluye características como
autenticación de nombre de usuario y contraseña, inicio de sesión, cierre de
sesión, recuperación de contraseña, entre otros. Puedes usarlo directamente en
tu proyecto Django y configurarlo según tus necesidades.
Ejemplo:
from django.contrib.auth import authenticate, login, logout

def login_view(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username,
password=password)
if user is not None:
login(request, user)
# Usuario autenticado, redirigir a una página
else:
# Credenciales inválidas, mostrar mensaje de
error
else:
# Mostrar formulario de inicio de sesión

def logout_view(request):
logout(request)
# Cierre de sesión exitoso, redirigir a una página
Permisos:
Django ofrece un sistema de control de acceso llamado "Permission Framework"
que permite definir y verificar los permisos de los usuarios en función de roles y
grupos. Puedes definir permisos a nivel de modelo y a nivel de vista.
Ejemplo:

6
from django.contrib.auth.decorators import login_required,
permission_required
from django.contrib.auth.mixins import LoginRequiredMixin,
PermissionRequiredMixin

@login_required
def my_view(request):
# Vista protegida, solo accesible para usuarios
autenticados
pass

@permission_required('myapp.change_object')
def edit_object(request, object_id):
# Vista protegida, solo accesible para usuarios con
permiso de 'change_object'
pass

class MyView(LoginRequiredMixin, PermissionRequiredMixin,


View):
permission_required = 'myapp.view_object'
# Vista basada en clase protegida, solo accesible para
usuarios aute
Cierre de sesión de usuarios:
Define una vista para el cierre de sesión donde los usuarios puedan hacer clic
en un botón o enlace para cerrar su sesión actual.
Dentro de esta vista, utiliza la función logout() para cerrar la sesión del usuario
actual.
Ejemplo:
from django.contrib.auth import logout
from django.shortcuts import redirect

def logout_view(request):
logout(request)
return redirect('home')
7
En estos ejemplos, login_view y logout_view son vistas de ejemplo que puedes
personalizar según las necesidades de tu aplicación. El código asume que tienes
plantillas (login.html en el primer ejemplo) y URLs configuradas para estas vistas.
Recuerda que, para utilizar la autenticación de Django, debes tener configurado
el sistema de autenticación en tu archivo de configuración (settings.py) y tener
las rutas adecuadas definidas en tu archivo urls.py.
Además, puedes utilizar decoradores como login_required para proteger vistas
y asegurarte de que solo los usuarios autenticados puedan acceder a ellas.
También puedes acceder a la información del usuario autenticado utilizando
request.user en tus vistas.
Es importante considerar la seguridad al gestionar la autenticación de usuarios.
Django proporciona medidas de seguridad incorporadas, como protección contra
ataques de falsificación de solicitudes entre sitios (CSRF) y almacenamiento
seguro de contraseñas utilizando hash y salting.
5. GESTIONAR CONTRASEÑAS
En Django, la gestión segura de contraseñas está integrada en el sistema de
autenticación. Django utiliza un algoritmo de hash y salting llamado PBKDF2
para almacenar las contraseñas de manera segura
Creación de un usuario:
Utiliza el gestor de usuarios (UserManager) proporcionado por Django para crear
un nuevo usuario.
El gestor de usuarios se encarga automáticamente de almacenar la contraseña
de manera segura utilizando PBKDF2.
Ejemplo:
from django.contrib.auth.models import User

# Crear un nuevo usuario


user = User.objects.create_user(username='john',
password='mypassword')

Autenticación de usuarios:
Utiliza la función authenticate() para verificar las credenciales de un usuario
(nombre de usuario y contraseña).
Django se encarga de verificar la contraseña almacenada en la base de datos
utilizando PBKDF2.
from django.contrib.auth import authenticate

# Verificar credenciales del usuario


8
user = authenticate(username='john', password='mypassword')
if user is not None:
# Credenciales válidas, continuar con el inicio de sesión
else:
# Credenciales inválidas, mostrar mensaje de error
Cambio de contraseña:
Utiliza el método set_password() del modelo de usuario para cambiar la
contraseña de un usuario existente.
El método set_password() se encarga automáticamente de generar el hash y
salting utilizando PBKDF2.
user = User.objects.get(username='john')
user.set_password('newpassword')
user.save()
Django se encarga de todo el proceso de gestión segura de contraseñas,
incluyendo la generación de salt, el almacenamiento seguro de contraseñas y la
verificación de credenciales al autenticar usuarios. Esto garantiza que las
contraseñas estén protegidas de manera adecuada.
Es importante destacar que, al utilizar el sistema de autenticación de Django, no
necesitas preocuparte por los detalles específicos de la gestión de contraseñas,
ya que el framework se encarga de ello de manera transparente y segura.

9
1. QUERYSETS
En Django, un QuerySet es una colección de objetos de un modelo específico
que se obtiene mediante consultas a la base de datos. Los QuerySets permiten
realizar operaciones y filtrar los datos de una manera sencilla y eficiente.
Recuperar todos los objetos de un modelo:
Utiliza el método all() para obtener todos los objetos de un modelo en particular.
from miapp.models import MiModelo
queryset = MiModelo.objects.all()

Filtrar objetos:
Utiliza el método filter() para filtrar los objetos según ciertos criterios.
Ejemplo:
queryset = MiModelo.objects.filter(nombre="John")
En Django, puedes utilizar una variedad de opciones para realizar consultas
basadas en comparaciones numéricas, de fecha y de cadenas de texto utilizando
los siguientes operadores:
exact:

Compara un valor exacto con el campo.


Ejemplo:
queryset = MiModelo.objects.filter(edad__exact=25)

iexact:

Compara un valor exacto sin distinguir entre mayúsculas y minúsculas.


Ejemplo:
queryset = MiModelo.objects.filter(nombre__iexact="john")

contains:

Comprueba si un valor está contenido en una cadena.


Ejemplo:
queryset = MiModelo.objects.filter(nombre__contains="John")

icontains:

1
Comprueba si un valor está contenido en una cadena sin distinguir entre
mayúsculas y minúsculas.
Ejemplo:
queryset =
MiModelo.objects.filter(nombre__icontains="john")

gt:

Comprueba si un valor es mayor que el campo.


Ejemplo:
queryset = MiModelo.objects.filter(edad__gt=18)

gte:

Comprueba si un valor es mayor o igual que el campo.


Ejemplo:
queryset = MiModelo.objects.filter(edad__gte=18)

lt:

Comprueba si un valor es menor que el campo.


Ejemplo:
queryset = MiModelo.objects.filter(edad__lt=30)

lte:

Comprueba si un valor es menor o igual que el campo.


Ejemplo:
queryset = MiModelo.objects.filter(edad__lte=30)

startswith:

Comprueba si una cadena comienza con un valor determinado.


Ejemplo:
queryset = MiModelo.objects.filter(nombre__startswith="J")
endswith:

2
Comprueba si una cadena termina con un valor determinado.
Ejemplo:
queryset = MiModelo.objects.filter(nombre__endswith="son")

Ordenar los objetos:


Utiliza el método order_by() para ordenar los objetos de acuerdo a uno o varios
campos.
Puedes especificar si el orden es ascendente o descendente.
Ejemplo:
queryset = MiModelo.objects.order_by('-fecha')
Realizar consultas complejas:
Puedes combinar múltiples condiciones y operadores para realizar consultas
complejas.
Utiliza los métodos filter(), exclude(), annotate(), Q() y otros para construir
consultas más sofisticadas.
Ejemplo:
from django.db.models import Q
queryset = MiModelo.objects.filter(Q(edad__gte=18) |
Q(profesion="programador"))

Obtener un único objeto:


Utiliza el método get() para obtener un único objeto que cumpla con ciertas
condiciones.
Si no se encuentra ningún objeto o se encuentran múltiples objetos, se generará
una excepción.
Ejemplo:
objeto = MiModelo.objects.get(id=1)
Realizar operaciones de agregación:
Puedes realizar operaciones de agregación, como contar, sumar, promediar, etc.,
en los QuerySets.
Utiliza los métodos count(), sum(), avg(), annotate(), entre otros.
Ejemplo:
total = MiModelo.objects.count()

3
suma_edades = MiModelo.objects.aggregate(Sum('edad'))

Estos son solo algunos ejemplos de las muchas funcionalidades que puedes
realizar con los QuerySets en Django. Los QuerySets son muy poderosos y te
permiten realizar consultas complejas de manera eficiente en tu base de datos.
Recuerda que los QuerySets son perezosos (lazy), lo que significa que la
evaluación de la consulta se realiza cuando se accede a los datos, lo que permite
un mejor rendimiento en las consultas.
Borrar
Para borrar objetos utilizando QuerySets en Django, puedes utilizar el método
delete() en el QuerySet deseado.

Filtrar los objetos que deseas borrar:


Utiliza los métodos de filtrado, como filter(), para obtener el conjunto de objetos
que deseas eliminar.
Ejemplo:
queryset = MiModelo.objects.filter(edad__gte=18)
Borrar los objetos:
Utiliza el método delete() en el QuerySet filtrado para eliminar los objetos de la
base de datos.
Ejemplo:
queryset.delete()

También puedes combinar el filtrado con otros métodos de consulta, como


exclude(), annotate(), etc., para obtener el conjunto de objetos específicos que
deseas eliminar.
Es importante tener en cuenta que el método delete() elimina los objetos de la
base de datos de forma irreversible, por lo que debes tener precaución al
utilizarlo. Asegúrate de haber filtrado correctamente los objetos que deseas
eliminar para evitar eliminar datos incorrectos o no deseados. Además, ten en
cuenta que el método delete() no desencadena los eventos pre_delete ni
post_delete de los modelos, por lo que si tienes lógica personalizada asociada a
estos eventos, tendrás que tenerlo en cuenta al utilizar delete().
Actualizar datos
Para actualizar objetos utilizando QuerySets en Django, puedes utilizar el
método update() en el QuerySet deseado. A continuación, te muestro cómo
puedes hacerlo:
Filtrar los objetos que deseas actualizar:

4
Utiliza los métodos de filtrado, como filter(), para obtener el conjunto de objetos
que deseas actualizar.
Ejemplo:
queryset = MiModelo.objects.filter(edad__gte=18)
Actualizar los objetos:
Utiliza el método update() en el QuerySet filtrado para realizar las actualizaciones
en los campos deseados.
Proporciona los nombres de los campos y los nuevos valores para actualizar los
objetos.
Ejemplo:
queryset.update(edad=20)

Ten en cuenta que el método update() actualiza los objetos directamente en la


base de datos, sin desencadenar eventos pre_save ni post_save en los modelos.
Además, el método update() no devuelve los objetos actualizados, solo devuelve
el número de filas afectadas.
Recuerda que al utilizar el método update(), las actualizaciones se aplican a
todos los objetos que cumplan con los criterios de filtrado. Asegúrate de haber
filtrado correctamente los objetos que deseas actualizar para evitar actualizar
datos incorrectos o no deseados.
2. SEGURIDAD
La protección de los datos de los usuarios es una parte esencial del diseño de
cualquier sitio web.
En la Seguridad del sitio tenemos que tener en cuenta que casi todos los ataques
tienen éxito cuando la aplicación web confía en los datos del navegador, por eso
la lección mas importante es nunca confiar en los datos del navegador . Esto
incluye GET de datos de solicitud en parámetros de URL, POST de datos,
encabezados HTTP y cookies, archivos subidos por usuarios, etc. Siempre hay
que verificar todos los datos entrantes.
Django esta diseñado para proteger de las amenazas más comunes:
Cross site scripting (XSS) (Secuencias de comandos entre sitios)
XSS es un término utilizado para describir una clase de ataques que permiten a
un atacante inyectar secuencias de comandos del lado del cliente a través del
sitio web en los navegadores de otros usuarios. Esto generalmente se logra
almacenando scripts maliciosos en la base de datos donde pueden recuperarse
y mostrarse a otros usuarios, o haciendo que los usuarios hagan clic en un
enlace que hará que el navegador del usuario ejecute el JavaScript del atacante.
El sistema de plantillas de Django lo protege contra la mayoría de los ataques
XSS escapando de caracteres específicos que son "peligrosos" en HTML.

5
El uso de plantillas de Django lo protege contra la mayoría de los ataques XSS.
Sin embargo, es posible desactivar esta protección, y la protección no se aplica
automáticamente a todas las etiquetas que normalmente no se completarían con
la entrada del usuario (por ejemplo, el help_textcampo en un formulario
generalmente no lo proporciona el usuario, por lo que Django no no escapar de
esos valores).
También es posible que los ataques XSS se originen en otras fuentes de datos
no confiables, como cookies, servicios web o archivos cargados (siempre que
los datos no estén lo suficientemente desinfectados antes de incluirlos en una
página). Si está mostrando datos de estas fuentes, es posible que deba agregar
su propio código de saneamiento.

Protección contra falsificación de solicitudes en sitios cruzados (CSRF)


Los ataques CSRF permiten que un usuario malintencionado ejecute acciones
usando las credenciales de otro usuario sin el conocimiento o consentimiento de
ese usuario.
La forma en que se habilita la protección es que incluye la {% csrf_token
%}etiqueta de plantilla en la definición de su formulario. Luego, este token se
representa en su HTML como se muestra a continuación, con un valor que es
específico para el usuario en el navegador actual.

<input type='hidden' name='csrfmiddlewaretoken'


value='0QRWHnYVg776y2l66mcvZqp8alrv4lb8S8lZ4ZJUWGZFA5VHrVfL
2mpH29YZ39PW'>
Django genera una clave específica de usuario/navegador y rechazará
formularios que no contengan el campo, o que contengan un valor de campo
incorrecto para el usuario/navegador.
Para usar este tipo de ataque, el hacker ahora tiene que descubrir e incluir la
clave CSRF para el usuario objetivo específico. Tampoco pueden usar el enfoque
"disperso" de enviar un archivo malicioso a todos los usuarios y esperar que uno
de ellos lo abra, ya que la clave CSRF es específica del navegador.
La protección CSRF de Django está activada de forma predeterminada. Siempre
debe usar la {% csrf_token %}etiqueta de plantilla en sus formularios y usarla
POSTpara solicitudes que puedan cambiar o agregar datos a la base de datos.

Otras protecciones
Django también proporciona otras formas de protección:

Protección de inyección SQL


6
Las vulnerabilidades de inyección SQL permiten a los usuarios malintencionados
ejecutar código SQL arbitrario en una base de datos, lo que permite acceder,
modificar o eliminar los datos independientemente de los permisos del usuario.
En casi todos los casos, accederá a la base de datos utilizando los conjuntos de
consultas/modelos de Django, por lo que el controlador de la base de datos
subyacente evitará correctamente el SQL resultante. Si necesita escribir
consultas sin procesar o SQL personalizado, deberá pensar explícitamente en
evitar la inyección de SQL.

Protección contra robo de clics


En este ataque, un usuario malintencionado secuestra los clics destinados a un
sitio de nivel superior visible y los dirige a una página oculta debajo. Esta técnica
podría usarse, por ejemplo, para mostrar un sitio bancario legítimo pero capturar
las credenciales de inicio de sesión en un lugar invisible <iframe>controlado por
el atacante. Django contiene protección contra el secuestro de clics en la forma
en X-Frame-Options middlewareque, en un navegador compatible, puede evitar
que un sitio se represente dentro de un marco.

Aplicación de SSL/HTTPS
SSL/HTTPS se puede habilitar en el servidor web para encriptar todo el tráfico
entre el sitio y el navegador, incluidas las credenciales de autenticación que, de
otro modo, se enviarían en texto sin formato (se recomienda encarecidamente
habilitar HTTPS). Si HTTPS está habilitado, Django proporciona una serie de
otras protecciones que puede usar:

SECURE_PROXY_SSL_HEADERse puede usar para verificar si el contenido es


seguro, incluso si proviene de un proxy que no es HTTP.
SECURE_SSL_REDIRECTse utiliza para redirigir todas las solicitudes HTTP a
HTTPS.
Utilice seguridad de transporte estricta HTTP (HSTS). Este es un encabezado
HTTP que informa a un navegador que todas las conexiones futuras a un sitio
en particular siempre deben usar HTTPS. Combinado con la redirección de
solicitudes HTTP a HTTPS, esta configuración garantiza que HTTPS siempre se
use después de que se haya producido una conexión exitosa. HSTS puede
configurarse con SECURE_HSTS_SECONDSy
SECURE_HSTS_INCLUDE_SUBDOMAINSo en el servidor web.
Use cookies 'seguras' configurando SESSION_COOKIE_SECUREy
CSRF_COOKIE_SECUREpara True. Esto asegurará que las cookies solo se
envíen a través de HTTPS.
Validación de encabezado de host

7
Usar ALLOWED_HOSTS para aceptar solo solicitudes de hosts confiables.

8
1. INTEGRACION DE APLICACIONES
La integración de aplicaciones, también conocida como integración de sistemas,
se refiere al proceso de combinar y conectar diferentes aplicaciones o sistemas
de software para que puedan funcionar de manera conjunta y compartir
información de manera eficiente.
En el entorno empresarial actual, es común que las organizaciones utilicen
múltiples aplicaciones y sistemas para llevar a cabo diferentes funciones y
procesos comerciales, como la gestión de recursos humanos, la contabilidad, el
inventario, el comercio electrónico, el servicio al cliente, entre otros. Estas
aplicaciones a menudo operan de manera independiente y pueden estar
basadas en tecnologías y plataformas diferentes.
La integración de aplicaciones tiene como objetivo superar las barreras
existentes entre estos sistemas, permitiendo el intercambio de datos y la
sincronización de actividades entre ellos. Esto se logra a través de diferentes
métodos y tecnologías, como interfaces de programación de aplicaciones (API),
servicios web, mensajes en cola, middleware, entre otros.
Al integrar aplicaciones, las organizaciones pueden lograr una mayor eficiencia
operativa, eliminar tareas manuales y duplicación de datos, mejorar la precisión
de la información y facilitar la toma de decisiones. Además, la integración de
aplicaciones puede impulsar la automatización de procesos empresariales,
mejorar la colaboración entre departamentos y proporcionar una visión más
completa y en tiempo real de la información empresarial.
2. EVOLUCION DE LA INTEGRACIÓN
La integración de aplicaciones ha evolucionado significativamente a lo largo del
tiempo para adaptarse a las cambiantes necesidades y avances tecnológicos.
• Integración punto a punto: En las primeras etapas, la integración de
aplicaciones se basaba principalmente en enlaces directos punto a punto
entre las aplicaciones. Cada aplicación se conectaba individualmente con
otras aplicaciones a través de interfaces personalizadas. Este enfoque
resultaba en una infraestructura de integración compleja y rígida, ya que
cualquier cambio en una aplicación requería modificaciones en todas las
aplicaciones conectadas.
• Middleware de integración: A medida que las organizaciones comenzaron
a utilizar una variedad de aplicaciones, se introdujo el middleware de
integración. Este enfoque implicaba la implementación de una capa de
software intermedia que actuaba como intermediario entre las
aplicaciones, permitiendo una comunicación más flexible y escalable. El
middleware de integración utilizaba adaptadores y conectores para
traducir y transmitir datos entre las aplicaciones.
• Integración basada en estándares: Con el tiempo, se establecieron
estándares de integración, como XML (eXtensible Markup Language),
SOAP (Simple Object Access Protocol) y REST (Representational State
Transfer). Estos estándares permitieron una mayor interoperabilidad entre

1
las aplicaciones y facilitaron la integración utilizando protocolos y formatos
comunes. Esto llevó a una mayor flexibilidad y reutilización de
componentes de integración.
• Servicios web y SOA (Arquitectura Orientada a Servicios): La evolución
de los servicios web y la adopción de la arquitectura orientada a servicios
(SOA) introdujeron un enfoque más modular y orientado a los servicios en
la integración de aplicaciones. Las aplicaciones se descomponen en
servicios individuales que se exponen a través de interfaces
estandarizadas. Esto permitió una mayor flexibilidad y reutilización al
combinar y orquestar servicios para cumplir con los procesos
empresariales.
• API y la nube: La proliferación de API (Interfaces de Programación de
Aplicaciones) y el auge de la computación en la nube han transformado
aún más la integración de aplicaciones. Las API proporcionan una forma
estándarizada de exponer funcionalidades y datos de las aplicaciones, lo
que facilita la integración y la creación de ecosistemas de aplicaciones
interconectadas. La nube ofrece una plataforma escalable y flexible para
alojar y orquestar servicios, permitiendo una integración más ágil y
basada en la demanda.

3. API
Una API o interfaz de programación de aplicaciones es un conjunto de
definiciones y protocolos que se usa para diseñar e integrar el software de las
aplicaciones.
Las API permiten que sus productos y servicios se comuniquen con otros, sin
necesidad de saber cómo están implementados.

2
Ejemplos.
Una empresa distribuidora de libros podría ofrecer a los clientes una aplicación
de nube que les permitiera a los empleados de la librería verificar la
disponibilidad de los libros con el distribuidor. El desarrollo de la aplicación podría
ser costoso, verse limitado por la plataforma, llevar mucho tiempo y requerir
mantenimiento permanente.
Otra opción es que la distribuidora de libros proporcionara una API para verificar
la disponibilidad en inventario. Existen varios beneficios de este enfoque:
 Permite que los clientes accedan a los datos con una API que les ayude
a añadir información sobre su inventario en un solo lugar.
 La distribuidora de libros podría realizar cambios en sus sistemas internos
sin afectar a los clientes, siempre y cuando el comportamiento de la API
fuera el mismo.
 Con una API disponible de forma pública, los desarrolladores que trabajan
para la distribuidora de libros, los vendedores o los terceros podrían
desarrollar una aplicación para ayudar a los clientes a encontrar los libros
que necesiten. Esto podría dar como resultado mayores ventas u otras
oportunidades comerciales.
3.1. API REMOTA
Las API remotas están diseñadas para interactuar en una red de
comunicaciones. La palabra remota indica que los recursos que administra la API
se encuentran fuera de la computadora que envía la solicitud. Dado que la red
de comunicaciones más usada es Internet, la mayoría de las API están
diseñadas de acuerdo con los estándares web. No todas las API remotas son
API web, pero se puede suponer que las API web son remotas.
Por lo general, las API web usan HTTP para los mensajes de solicitud y
proporcionan una definición de la estructura de los mensajes de respuesta. Estos
mensajes de respuesta suelen ser archivos XML o JSON, que son los formatos

3
preferidos, porque presentan los datos de manera tal que otras aplicaciones
puedan manipularlos fácilmente.
3.2. SOAP y REST
Las API diseñadas con SOAP usan XML para el formato de sus mensajes y
reciben solicitudes a través de HTTP o SMTP. Con SOAP, es más fácil que las
aplicaciones que funcionan en entornos distintos o están escritas en diferentes
lenguajes compartan información.
Las API web que funcionan con las limitaciones de arquitectura REST se llaman
API de RESTful. La diferencia más básica entre ambas es que SOAP es un
protocolo, mientras que REST es un estilo de arquitectura. Esto significa que no
hay ningún estándar oficial para las API web de RESTful, pero debe cumplir con
lo siguiente: Arquitectura cliente-servidor, Sistema sin estado, Capacidad de
almacenamiento en caché, Sistema en capas, Disponibilidad del código según
se solicite e Interfaz uniforme

4. ARQUITECTURA DE MICROSERVICIOS
Las arquitecturas de microservicios se parecen a los patrones SOA en que los
servicios son especializados y no tienen conexión directa. Pero además,
descomponen las arquitecturas tradicionales en partes más pequeñas.
Los servicios de la arquitectura de microservicios usan un marco de mensajería
común, como las API de RESTful. Utilizan API de RESTful para comunicarse
entre sí, sin necesidad de operaciones complejas de conversión de datos ni
capas de integración adicionales.
Usar las API de RESTful permite e incluso fomenta una distribución más rápida
de nuevas funciones y actualizaciones.
Cada servicio es independiente. Un servicio se puede reemplazar, mejorar o
abandonar, sin afectar los demás servicios de la arquitectura. Esta arquitectura
liviana optimiza los recursos distribuidos o en la nube y admite la adaptación
dinámica de los servicios individuales.

5. DJANGO REST FRAMEWORK (DRF)


Django REST Framework (DRF) es una potente biblioteca de Python que se
utiliza para construir API (Application Programming Interfaces) web en
aplicaciones Django. Proporciona una serie de utilidades y herramientas que
simplifican el proceso de desarrollo de API y facilitan la implementación de las
mejores prácticas.
DRF se basa en el marco de trabajo Django, un popular marco de desarrollo web
de alto nivel en Python. Django ya ofrece soporte para crear aplicaciones web
completas, pero DRF se enfoca específicamente en la construcción de API
RESTful.
4
Algunas de las ventajas que ofrece DRF a la hora de implementar APIs son las
siguientes:
• API navegable desde el browser lo que agiliza el trabajo de los
desarrolladores
• Integración con autenticación basada en OAuth1a o OAuth2.
• Serialización de datos a partir de ORM u otros orígenes.
• Muy buena documentación y una amplia comunidad al ser open source

5.1. SERIALIZACION
La serialización es el proceso de convertir un objeto o estructura de datos en un
formato que pueda ser almacenado o transmitido, generalmente en forma de una
secuencia de bytes. El objetivo de la serialización es permitir la persistencia de
los datos o su transferencia a través de una red, de manera que puedan ser
reconstruidos o utilizados en otro contexto.
La serialización es particularmente útil en entornos de programación distribuida,
donde los datos necesitan ser enviados entre diferentes sistemas o
componentes que pueden estar utilizando diferentes lenguajes de programación
o tener diferentes representaciones internas de los datos.
Cuando un objeto o estructura de datos se serializa, se convierte en una
representación que puede ser almacenada en un archivo, base de datos o
transmitida a través de una red. Esta representación puede ser en forma de texto,
como JSON (JavaScript Object Notation) o XML (eXtensible Markup Language),
o en forma binaria, como en el caso de protocolos de serialización binaria
específicos.
El proceso de serialización implica la conversión de los datos en una forma
estándar y portátil, que puede ser interpretada y reconstruida por otros sistemas
o componentes. En el proceso inverso, conocido como deserialización, la
secuencia de bytes se reconstruye en su forma original, lo que permite que los
datos se utilicen o manipulen según sea necesario.
DRF proporciona un sistema de serialización que convierte los objetos de Django
en tipos de datos nativos de Python, como JSON, y viceversa. Esto facilita la
manipulación y transferencia de datos entre las API y las aplicaciones cliente.
5.2. AUTENTICACION
DRF proporciona mecanismos integrados para la autenticación y autorización de
las API. Soporta diferentes métodos de autenticación, como tokens, sesiones y
JSON Web Tokens (JWT), y permite configurar permisos y restricciones de
acceso para proteger las API.
• Básica, Es el método más sencillo pero inseguro, ya que se basa en
enviar el usuario y su contraseña codificadas en Base64 en las cabeceras
de cada petición. Tened en cuenta que la codificación en Base64 es una

5
formalidad y es tan sencillo descodificar una cadena en este formato como
pasar el valor a una función de cualquier lenguaje de programación.
• API Keys, Otro sistema bastante utilizado es enviar una key facilitada por
la API que sustituye las credenciales de un usuario. Muchas APIs públicas
ofrecen este sistema porque es fácil añadirle un límite de peticiones
diarias, pero en la práctica es sustituir la cadena de autenticación por la
clave que se provee a cliente.
• Bearer, También conocida como Token Authentication se basa en proveer
al cliente de un "código" después de identificarse por primera vez. En lugar
de enviar todo el rato el usuario y su contraseña, el cliente envía ese
código generado por el backend en la cabecera de las peticiones. Es igual
de inseguro que la autenticación básica, pero como mínimo no se mandan
las credenciales en cada petición.
• JSON Web Tokens, Los JWT son un estándar abierto de la industria para
representar peticiones de forma "segura" entre dos partes. Este sistema
añade una capa extra de seguridad en los tokens, con mecanismos de
decodificación, verificación y renovación de los mismos.
• OAuth2, Este sistema de autenticación permite compartir información
entre sitios sin compartir las credenciales del usuario. En lugar de generar
el token en nuestro backend se delega este proceso una plataforma de
terceros, de manera que no necesitamos almacenar el usuario y la
contraseña en la base de datos. Oauth2 es muy cómodo, pero si tenemos
interés en almacenar información del usuario en nuestra base de datos
igualmente necesitaremos implementar un sistema de usuarios y pedirle
la información a esas plataformas de terceros. Casi nunca se utiliza como
sistema único de autenticación, sino como apoyo de nuestro propio
sistema

5.3. VIEWSETS Y ROUTERS


Las views no son más que extensiones de las class-view de django, pero
mejoradas para simplificarnos el link con los routers, los serializadores y los
modelos y en lugar de renderizar un html como respuesta devolver de forma
sencilla un json, xml u otra estructura de datos que nos interese que devuelva
nuestra API.
Los routers son una herramienta que nos permiten definir las urls de nuestro API
de una manera sencilla y ordenada. Básicamente nos permiten definir
limpiamente qué método de una class view se ejecutará al llegar una petición
HTTP contra un path concreto usando un verbo HTTP u otro. En resumen nos
permiten definir cómodamente conjuntos de urls y nos encaminan a nuestros
métodos en función del verbo HTTP (GET, POST, PUT, PATCH)

6. INSTALAR DJANGO REST FRAMEWORK (DRF)


1. Instalar DRF
6
Lo primero que vamos a hacer es instalar DJANGO REST FRAMEWORK, para
tal motivo vamos a seguir trabajando en el entorno virtual creado en el sprint
anterior, pero ahora vamos a agregar las librerías de DRF utilizando pip install
djangorestframework

2. Crear Proyecto
Ahora vamos a crear un proyecto nuevo DJANGO para comenzar a realizar
nuestra API
django-admin startproject nueva_api
En este proyecto vamos a utilizar la configuración por defecto que trae (lenguaje,
BD, etc). Por eso vamos a migrar las aplicaciones por defecto python manage.py
migrate
3. Crear Aplicación
Vamos a crear la aplicación libros, este proyecto contempla la generación de una
API CRUD de libros.
python manage.py startapp libros

CRUD (Create, Read, Update, Delete)


Crear, leer, actualizar y eliminar, o CRUD, son las cuatro funciones principales
que se utilizan para interactuar con las aplicaciones de bases de datos. El
acrónimo es popular entre los programadores, ya que brinda un recordatorio
rápido de qué funciones de manipulación de datos se necesitan para que una
aplicación este completa.
Muchos lenguajes de programación y protocolos tienen su propio equivalente de
CRUD, a menudo con ligeras variaciones en cómo se nombran las funciones y
qué hacen.
Por ejemplo, como vimos en el sprint 5 de SQL, estas cuatro funciones se
representan con las sentencias INSERT, SELECT, UPDATE y DELETE.
Cuando desarrollamos una API, generalmente ofrecemos a los que van a
utilizarla operaciones CRUD. Como vimos en la introducción de esta unidad, las
API se comunican con los clientes mediante el protocolo HTTP, que tiene su
propio conjunto de métodos para la manipulación de datos: GET, POST,

7
DELETE, PUT y PATCH, entre otros. Hay una relación entre los métodos
propuesto por HTTP y las funciones CRUD:
CRUD HTTP

CREATE POST/PUT

READ GET

UPDATE PUT/POST/PATCH

DELETE DELETE

Algo que tenemos que tener en cuenta es que las API REST no se limitan a las
funciones CRUD. Por ejemplo, una API REST aún puede permitir que los clientes
reinicien un servidor, aunque eso no equivale a ninguna de las cuatro funciones
CRUD, siempre que implique el uso de métodos HTTP apropiados.
Volviendo a nuestra aplicación sobre libros, vamos a generar los siguientes
“endpoint” con las funciones que generalmente proveemos cuando hacemos una
API
• Endpoint que liste libros.
• Endpoint que nos muestre los detalles de un libro concreto.
• Endpoint para añadir un libro.
• Endpoint para actualizar un libro existe.
• Endpoint que borre un libro existe.
Los endpoints son las URLs HTTP que reciben o retornan información de una
WEB API.
Ahora que entendimos nuestra aplicación, no tenemos que olvidar de configurar
las aplicaciones en el archivo settings.py

8
python manage.py makemigrations python manage.py migrate
Adicionalmente vamos a crear un superusuario
python manage.py createsuperuser
Finalmente, para probar que todo quedo instalado correctamente, levantamos el
servidor
python manage.py runserver

7. SERIALIZADOR
En Django REST Framework (DRF), un serializador es una clase que permite
convertir objetos complejos de Django en representaciones más simples, como
JSON, y viceversa. El serializador se encarga de la serialización y deserialización

9
de los datos, facilitando la transferencia de información entre la API y las
aplicaciones cliente.
Para usar un serializador en DRF, se deben seguir los siguientes pasos:
• Definir el serializador: Se crea una clase que hereda de la clase base
serializers.Serializer de DRF. En esta clase, se especifican los campos
que se desean serializar y se definen las reglas de validación, si es
necesario.
from rest_framework import serializers

class MiSerializador(serializers.Serializer):
campo1 = serializers.CharField(max_length=100)
campo2 = serializers.IntegerField()

• Serializar datos: Para convertir un objeto o conjunto de datos en una


representación serializada, se instancia el serializador y se le pasa el
objeto o datos que se desean serializar.
datos = {'campo1': 'valor1', 'campo2': 42}
serializador = MiSerializador(datos)
serializado = serializador.data
El resultado serializado contendrá una representación de los datos en el formato
especificado por el serializador, en este caso, como un diccionario.
• Deserializar datos: Para convertir una representación serializada en
objetos o datos de Django, se instancia el serializador y se le pasa la
representación serializada.
datos_serializados = {'campo1': 'valor1', 'campo2': 42}
serializador = MiSerializador(data=datos_serializados)
if serializador.is_valid():
deserializado = serializador.validated_data

El resultado deserializado contendrá los datos deserializados en un formato que


pueda ser utilizado por la aplicación de Django.
Los serializadores también se pueden utilizar en las vistas de DRF para manejar
la validación de datos entrantes y la respuesta de la API. Por ejemplo, en una
vista basada en clases de DRF:

from rest_framework.views import APIView


from rest_framework.response import Response

10
class MiVista(APIView):
def post(self, request):
serializador = MiSerializador(data=request.data)
if serializador.is_valid():
# Realizar acciones con los datos deserializados
return Response("Datos válidos")
else:
return Response(serializador.errors,
status=400)
En este ejemplo, el serializador se utiliza para validar los datos recibidos en la
solicitud POST y proporcionar una respuesta adecuada según el resultado de la
validación.
8. VIEWSETS
En Django REST Framework (DRF), un ViewSet es una clase que combina la
funcionalidad de múltiples vistas en una sola entidad coherente. Proporciona una
forma conveniente de definir las operaciones CRUD (Crear, Leer, Actualizar,
Eliminar) en un conjunto de datos, y se utiliza para construir rápidamente vistas
de API RESTful.
Un ViewSet en DRF puede ser utilizado de dos maneras diferentes: ViewSet
básico y ViewSet con enrutamiento automático.
ViewSet básico:
• Se define una clase que hereda de rest_framework.viewsets.ViewSet.
• Se definen métodos de acción para cada operación CRUD que se desee
soportar (por ejemplo, create, list, retrieve, update, partial_update,
destroy).
• Dentro de cada método de acción, se implementa la lógica
correspondiente.
Ejemplo:

from rest_framework import viewsets

class MiViewSet(viewsets.ViewSet):
def list(self, request):

11
# Implementar lógica para obtener una lista de
objetos
return Response(...)

def create(self, request):


# Implementar lógica para crear un nuevo objeto
return Response(...)

def retrieve(self, request, pk=None):


# Implementar lógica para obtener un objeto
específico
return Response(...)

def update(self, request, pk=None):


# Implementar lógica para actualizar un objeto
existente
return Response(...)

def destroy(self, request, pk=None):


# Implementar lógica para eliminar un objeto
existente
return Response(...)

ViewSet con enrutamiento automático:


• Se define una clase que hereda de
rest_framework.viewsets.ModelViewSet.
• Se especifica el modelo asociado al ViewSet.
• DRF automáticamente genera las acciones CRUD basadas en el modelo
y los enlaza a las URL correspondientes.
Ejemplo:
from rest_framework import viewsets

class MiModeloViewSet(viewsets.ModelViewSet):
queryset = MiModelo.objects.all()

12
serializer_class = MiModeloSerializer

En este ejemplo, MiModelo es el modelo de Django asociado al ViewSet y


MiModeloSerializer es el serializador utilizado para serializar/deserializar los
objetos.
Una vez definido el ViewSet, se debe enlazar a las URLs correspondientes en el
archivo urls.py de la aplicación Django. Esto se puede hacer utilizando
DefaultRouter en el caso del enrutamiento automático o definiendo las URLs
manualmente en el caso del ViewSet básico.
9. ROUTERS
En Django, un router es una clase que se utiliza para mapear las URLs a las
vistas correspondientes en una aplicación web. Los routers son especialmente
útiles en el contexto de las aplicaciones basadas en Django REST Framework
(DRF) para definir las rutas de las API y asociarlas a las vistas.
Un router en Django generalmente se define en el archivo urls.py de la aplicación
y se utiliza para enlazar las URLs a las vistas o conjuntos de vistas
correspondientes.
Para utilizar un router en Django, se siguen los siguientes pasos:
Importar el router correspondiente:
from django.urls import routers
Definir las vistas o conjuntos de vistas:
# Ejemplo de vistas individuales
from miapp.views import MiVista
# Ejemplo de ViewSet
from miapp.viewsets import MiViewSet
Crear una instancia del router:
router = routers.DefaultRouter()
Registrar las vistas o conjuntos de vistas en el router:
# Registrar una vista individual
router.register(r'mipath', MiVista, basename='mi-vista')
# Registrar un ViewSet
router.register(r'mipath', MiViewSet, basename='mi-
viewset')

En el ejemplo anterior, r'mipath' es la URL a la cual se asociará la vista o el


ViewSet. MiVista y MiViewSet son las vistas o ViewSets correspondientes que

13
se desea enlazar. basename es un nombre opcional que se utiliza para generar
los nombres de las rutas relacionadas.
Incluir las rutas generadas por el router en el archivo urls.py de la aplicación:
urlpatterns = [
# Otras URLs de la aplicación
# ...

# Incluir las rutas generadas por el router


path('', include(router.urls)),
]
Al incluir las rutas generadas por el router utilizando include(router.urls), se
enlazan las URLs definidas en el router a las vistas o ViewSets correspondientes.
Eejmplo
Supongamos que tienes una aplicación llamada miapp y deseas definir las rutas
para una API RESTful utilizando Django REST Framework. En este ejemplo,
vamos a utilizar un ViewSet para gestionar los recursos relacionados con los
libros.
En el archivo urls.py de la aplicación miapp, importa el router y las vistas o
ViewSets correspondientes:
from django.urls import include, path
from rest_framework import routers
from miapp.viewsets import LibroViewSet

router = routers.DefaultRouter()
router.register(r'libros', LibroViewSet, basename='libros')

A continuación, incluye las rutas generadas por el router en las URLs de la


aplicación:
urlpatterns = [
# Otras URLs de la aplicación
# ...

# Incluir las rutas generadas por el router


path('api/', include(router.urls)),

14
]

En este caso, todas las rutas para la API de libros se agregarán bajo el prefijo
/api/.
En el archivo viewsets.py de la aplicación miapp, define el ViewSet para los
libros:
from rest_framework import viewsets
from miapp.models import Libro
from miapp.serializers import LibroSerializer

class LibroViewSet(viewsets.ModelViewSet):
queryset = Libro.objects.all()
serializer_class = LibroSerializer

Aquí, LibroViewSet hereda de viewsets.ModelViewSet y se especifica el modelo


Libro y el serializador LibroSerializer.
Con estos pasos, has configurado un router en Django y has enlazado las rutas
/api/libros/ a las operaciones CRUD gestionadas por el ViewSet LibroViewSet.
Ahora, podrás acceder a las siguientes rutas para interactuar con la API de libros:
• /api/libros/: Devuelve la lista de libros y permite crear un nuevo libro.
• /api/libros/<id>/: Devuelve los detalles de un libro específico, así como
permite actualizar o eliminar ese libro.
Recuerda que debes definir los modelos correspondientes, como Libro, y los
serializadores, como LibroSerializer, en la aplicación miapp. Además, asegúrate
de tener todas las dependencias instaladas, incluyendo Django y Django REST
Framework.

15
1. REQUEST
En Django REST Framework (DRF), el objeto request se refiere al objeto de
solicitud que se pasa a las vistas basadas en clases o funciones al manejar una
solicitud HTTP. El objeto request encapsula toda la información relacionada con
la solicitud entrante, como los parámetros de la URL, los datos enviados, las
cabeceras, las cookies y más.
El objeto request proporciona acceso a diferentes atributos y métodos que te
permiten interactuar y obtener información relevante sobre la solicitud. Algunos
de los atributos y métodos comunes que se pueden utilizar con el objeto request
en DRF incluyen:
• request.method: El método HTTP utilizado en la solicitud (GET, POST,
PUT, DELETE, etc.).
• request.GET: Un diccionario que contiene los parámetros de la URL
enviados con la solicitud.
• request.data: Los datos enviados en la solicitud (en el cuerpo de la
solicitud), generalmente utilizado en solicitudes POST, PUT y PATCH.
• request.user: El objeto de usuario autenticado asociado con la solicitud,
si la autenticación está habilitada.
• request.query_params: Un diccionario que contiene los parámetros de la
URL enviados con la solicitud, similar a request.GET.
• request.headers: Un diccionario que contiene las cabeceras de la
solicitud.
• request.COOKIES: Un diccionario que contiene las cookies enviadas con
la solicitud.
Estos son solo algunos ejemplos de cómo puedes acceder y utilizar el objeto
request en DRF. Dependiendo de tus necesidades específicas, puedes utilizar
otros atributos y métodos disponibles en el objeto request para obtener más
información o realizar acciones adicionales relacionadas con la solicitud
entrante.
Recuerda que en DRF, el objeto request se pasa automáticamente como el
primer parámetro a las vistas basadas en clases o funciones cuando manejan
una solicitud HTTP, y no necesitas crearlo o inicializarlo manualmente.
2. RESPONSE
En Django REST Framework (DRF), el objeto Response es una clase que se
utiliza para generar y enviar respuestas HTTP desde una vista o una API.
Proporciona una forma conveniente de crear y enviar respuestas con formato
adecuado, como JSON, XML, HTML, etc.
El objeto Response se utiliza para devolver una respuesta desde una vista o una
función de vista en DRF. Puedes utilizarlo para devolver datos en formato
estructurado, como diccionarios o listas, y DRF se encargará de serializarlos en
el formato adecuado según el encabezado Accept de la solicitud.

1
Aquí tienes un ejemplo básico de cómo utilizar el objeto Response en DRF:
from rest_framework.response import Response
from rest_framework.views import APIView

class HelloView(APIView):
def get(self, request):
data = {'message': 'Hola, mundo!'}
return Response(data)

En el ejemplo anterior, HelloView es una clase de vista basada en clase en DRF


que responde a solicitudes GET. Cuando se realiza una solicitud GET a esta
vista, se crea un diccionario data que contiene un mensaje de saludo. Luego, se
devuelve una instancia de Response con el diccionario data. DRF se encargará
de serializar automáticamente el diccionario en el formato adecuado
(generalmente JSON) antes de enviar la respuesta al cliente.
El objeto Response también proporciona métodos y atributos adicionales para
personalizar y controlar las respuestas, como configurar el código de estado,
establecer encabezados personalizados, establecer cookies y más. Puedes
explorar la documentación oficial de DRF para obtener más información sobre
las opciones y funcionalidades disponibles con el objeto Response.

3. CODIGOS DE ESTADO
En Django REST Framework (DRF), los códigos de estado se manejan utilizando
las respuestas HTTP proporcionadas por el propio framework. DRF utiliza la
clase Response para generar respuestas con los códigos de estado apropiados.
DRF proporciona una serie de constantes predefinidas para los códigos de
estado más comunes en la clase status de rest_framework, que puedes importar
y utilizar en tus vistas y funciones de vista. Algunos ejemplos de códigos de
estado disponibles en DRF incluyen:
• status.HTTP_200_OK: Indica que la solicitud se ha procesado con éxito.
• status.HTTP_201_CREATED: Indica que la solicitud ha tenido éxito y ha
resultado en la creación de un nuevo recurso.
• status.HTTP_400_BAD_REQUEST: Indica que la solicitud del cliente es
incorrecta o no se puede procesar.
• status.HTTP_404_NOT_FOUND: Indica que el recurso solicitado no se
ha encontrado en el servidor.
• status.HTTP_500_INTERNAL_SERVER_ERROR: Indica un error interno
en el servidor al procesar la solicitud.
Ejemplo

2
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class MyView(APIView):
def get(self, request):
data = {'message': 'Hello, world!'}

if some_condition:
return Response(data,
status=status.HTTP_200_OK)
else:
return Response({'error': 'Something went
wrong'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
En el ejemplo anterior, se utiliza la clase status de DRF para definir los códigos
de estado en las respuestas. Dependiendo de una condición específica
(some_condition), se devuelve una respuesta con el código de estado apropiado.
En caso de que ocurra un error, se devuelve una respuesta con el código de
estado HTTP 500.
Usar las constantes predefinidas de status de DRF en lugar de los números de
código de estado en bruto hace que el código sea más legible y comprensible,
ya que proporciona un contexto claro sobre el resultado de la solicitud.
4. EMPAQUETADO DE API VIEWS
El "empaquetado" o "wrapping" de vistas de API se refiere a la técnica utilizada
en Django REST Framework (DRF) para modificar o extender el comportamiento
de una vista de API existente mediante la creación de una nueva vista que
envuelve o envuelve a la vista original.
El empaquetado de vistas de API en DRF se logra utilizando decoradores o
clases de envoltura para modificar el comportamiento de la vista subyacente.
Estos decoradores o clases agregan lógica adicional antes o después de la
ejecución de la vista original, lo que permite realizar acciones adicionales o
personalizar el flujo de la solicitud.
Existen varios casos de uso comunes para el empaquetado de vistas de API en
DRF, como:

3
• Autenticación y autorización: Puedes envolver una vista para agregar
lógica de autenticación o autorización adicional antes de que se ejecute
la vista. Por ejemplo, puedes asegurarte de que el usuario esté
autenticado antes de permitir el acceso a la vista.
• Registro y análisis: Puedes envolver una vista para realizar un
seguimiento del tiempo de ejecución, registrar datos o realizar análisis
antes o después de que se ejecute la vista. Esto puede ser útil para
recopilar métricas, generar registros o realizar tareas de monitoreo.
• Transformación de datos: Puedes envolver una vista para transformar o
modificar los datos antes de que se devuelvan como respuesta. Esto
puede incluir la manipulación de la estructura de los datos, la agregación
de información adicional o la aplicación de reglas de negocio específicas.
Ejemplo
from rest_framework.decorators import api_view
from rest_framework.response import Response

def log_request(view_func):
def wrapper(request, *args, **kwargs):
# Lógica de registro antes de la ejecución de la
vista
print(f"Request received: {request.method}
{request.path}")
response = view_func(request, *args, **kwargs)
# Lógica de registro después de la ejecución de la
vista
print(f"Response sent: {response.status_code}")
return response
return wrapper

@api_view(['GET'])
@log_request
def my_view(request):
# Lógica de la vista
data = {'message': 'Hello, world!'}
return Response(data)

4
En el ejemplo anterior, se define el decorador log_request que envuelve la vista
my_view. El decorador log_request agrega lógica de registro antes y después de
la ejecución de la vista. Al realizar una solicitud GET a my_view, la función
wrapper dentro del decorador se ejecutará primero para realizar el registro y
luego llamará a la vista original my_view. Después de la ejecución de la vista, se
realizará más lógica de registro antes de devolver la respuesta.
El empaquetado de vistas de API en DRF proporciona flexibilidad para
personalizar y extender el comportamiento de las vistas existentes, lo que facilita
la implementación de características adicionales o la adaptación a requisitos
específicos de tu aplicación.
5. API VIEW
La clase APIView es una clase base proporcionada por Django REST Framework
(DRF) que se utiliza para definir vistas de API en Django. Proporciona una
implementación flexible y completa de una vista de API y ofrece una serie de
métodos y características útiles para trabajar con solicitudes y respuestas HTTP.
Para utilizar la clase APIView, debes crear una subclase de ella y definir los
métodos de manejo de solicitudes HTTP relevantes, como get(), post(), put(),
delete(), entre otros, según tus necesidades. Estos métodos se ejecutarán según
el tipo de solicitud HTTP recibida y puedes personalizar su implementación para
realizar acciones específicas y devolver respuestas adecuadas.
from rest_framework.views import APIView
from rest_framework.response import Response

class HelloView(APIView):
def get(self, request):
data = {'message': 'Hello, world!'}
return Response(data)
En el ejemplo anterior, se define la clase HelloView como una subclase de
APIView y se implementa el método get(). Cuando se recibe una solicitud GET a
esta vista, se ejecuta el método get() y se devuelve una respuesta con un
mensaje de saludo en formato JSON utilizando la clase Response.
Además de los métodos de manejo de solicitudes HTTP, la clase APIView
proporciona otros métodos y características útiles, como autenticación y
autorización, manejo de errores, paginación, control de versiones y más. Puedes
personalizar y configurar estos aspectos según tus requisitos.
Ejemplo

from rest_framework.views import APIView

5
from rest_framework.response import Response
from rest_framework.authentication import
SessionAuthentication
from rest_framework.pagination import LimitOffsetPagination

class MyListView(APIView):
authentication_classes = [SessionAuthentication]
pagination_class = LimitOffsetPagination

def get(self, request):


queryset = MyModel.objects.all()
paginated_queryset =
self.pagination_class().paginate_queryset(queryset,
request)
serialized_data =
MyModelSerializer(paginated_queryset, many=True)
return
self.pagination_class().get_paginated_response(serialized_d
ata.data)

En este ejemplo, se define la clase MyListView que es una subclase de APIView.


Se configura la autenticación de sesión utilizando SessionAuthentication y se
habilita la paginación utilizando LimitOffsetPagination. En el método get(), se
obtiene el conjunto de consultas (queryset), se aplica la paginación a través de
paginate_queryset(), se serializa el resultado y se devuelve una respuesta
paginada utilizando get_paginated_response().
La clase APIView es una herramienta poderosa para crear vistas de API en DRF,
ya que proporciona una base sólida y flexible con muchas funcionalidades
incorporadas. Puedes personalizarla aún más agregando mixins, configurando
autenticación, autorización, paginación y otras características según las
necesidades de tu proyecto.
6. API POST
Un API POST es un tipo de solicitud HTTP utilizada para enviar datos o crear
recursos en un servidor. La solicitud POST se utiliza para enviar información
desde el cliente al servidor para su procesamiento.

En Django REST Framework (DRF), puedes implementar un API POST


utilizando una vista de clase basada en APIView o utilizando un ViewSet.

6
Ejemplo de cómo implementar un API POST utilizando DRF API VIEW:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class MyPostView(APIView):
def post(self, request):
# Acceder a los datos enviados en la solicitud POST
data = request.data

# Validar y procesar los datos


# ...

# Crear un nuevo recurso


# ...

# Devolver una respuesta apropiada


if resource_created:
return Response({'message': 'Recurso creado
correctamente'}, status=status.HTTP_201_CREATED)
else:
return Response({'error': 'Error al crear el
recurso'}, status=status.HTTP_400_BAD_REQUEST)
En el ejemplo anterior, se define la clase MyPostView como una subclase de
APIView y se implementa el método post(). Dentro de este método, puedes
acceder a los datos enviados en la solicitud POST utilizando request.data.
Luego, puedes realizar la validación y el procesamiento necesarios en los datos
recibidos.

Después de procesar los datos, puedes crear un nuevo recurso en tu base de


datos o en cualquier otro sistema según tus necesidades.

7
Finalmente, debes devolver una respuesta apropiada. En el ejemplo, si el recurso
se creó correctamente, se devuelve una respuesta con el código de estado HTTP
201 CREATED. Si ocurrió algún error durante el proceso de creación, se
devuelve una respuesta con el código de estado HTTP 400 BAD REQUEST.
Es importante tener en cuenta que en este ejemplo se utilizan los códigos de
estado HTTP predefinidos proporcionados por DRF a través de la clase status.
Puedes utilizar estos códigos o especificar tus propios códigos de estado según
tus requisitos específicos.
7. API GET
Un API GET es un tipo de solicitud HTTP utilizado para recuperar información o
recursos del servidor. La solicitud GET se utiliza para solicitar datos del servidor
sin realizar cambios en ellos.
En Django REST Framework (DRF), puedes implementar un API GET utilizando
una vista de clase basada en APIView o utilizando un ViewSet.

Ejemplo de cómo implementar un API GET utilizando DRF:


from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class MyGetView(APIView):
def get(self, request):
# Obtener los datos o recursos necesarios
queryset = MyModel.objects.all()

# Realizar cualquier filtrado o manipulación


adicional
# ...

# Serializar los datos


serializer = MyModelSerializer(queryset, many=True)

# Devolver los datos serializados en la respuesta


return Response(serializer.data,
status=status.HTTP_200_OK)
8
En el ejemplo anterior, se define la clase MyGetView como una subclase de
APIView y se implementa el método get(). Dentro de este método, puedes
realizar cualquier lógica necesaria para obtener los datos o recursos necesarios
de tu base de datos o de cualquier otra fuente.
Una vez que obtienes los datos, puedes realizar filtrado, manipulación o
cualquier otra operación adicional que necesites. En este ejemplo, se utiliza el
modelo MyModel y su correspondiente serializador MyModelSerializer.
Después de realizar las operaciones necesarias, se serializan los datos
utilizando el serializador y se devuelven en la respuesta utilizando la clase
Response de DRF. Los datos serializados se pasan como argumento a
Response, y se devuelve una respuesta con el código de estado HTTP 200 OK.
Es importante tener en cuenta que en este ejemplo se utilizan los códigos de
estado HTTP predefinidos proporcionados por DRF a través de la clase status.
Puedes utilizar estos códigos o especificar tus propios códigos de estado según
tus requisitos específicos.
8. API DELETE
Un API DELETE es un tipo de solicitud HTTP utilizado para eliminar un recurso
específico en un servidor. La solicitud DELETE se utiliza para indicar al servidor
que se debe eliminar el recurso identificado por una URL determinada.
En Django REST Framework (DRF), puedes implementar un API DELETE
utilizando una vista de clase basada en APIView o utilizando un ViewSet.
Ejemplo de cómo implementar un API DELETE utilizando DRF:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class MyDeleteView(APIView):
def delete(self, request, pk):
# Obtener el recurso específico a eliminar
try:
instance = MyModel.objects.get(pk=pk)
except MyModel.DoesNotExist:
return Response({'error': 'Recurso no
encontrado'}, status=status.HTTP_404_NOT_FOUND)

# Realizar cualquier validación o lógica adicional

9
# ...

# Eliminar el recurso
instance.delete()

# Devolver una respuesta apropiada


return Response({'message': 'Recurso eliminado
correctamente'}, status=status.HTTP_204_NO_CONTENT)

En el ejemplo anterior, se define la clase MyDeleteView como una subclase de


APIView y se implementa el método delete(). Dentro de este método, se espera
que se proporcione un parámetro pk que representa la clave primaria del recurso
a eliminar.
Primero, se intenta obtener el recurso específico utilizando la clave primaria
proporcionada. Si el recurso no existe, se devuelve una respuesta con el código
de estado HTTP 404 NOT FOUND indicando que el recurso no fue encontrado.
Luego, puedes realizar cualquier validación o lógica adicional necesaria antes de
eliminar el recurso. En este ejemplo, se utiliza el método delete() del objeto
instance para eliminar el recurso de la base de datos.
Finalmente, se devuelve una respuesta con el código de estado HTTP 204 NO
CONTENT para indicar que el recurso fue eliminado correctamente. En este
caso, no se devuelve ningún contenido en la respuesta, ya que el recurso ha sido
eliminado.
Es importante tener en cuenta que puedes personalizar y adaptar la lógica de
eliminación según tus requisitos específicos. Además, asegúrate de implementar
las adecuadas consideraciones de seguridad y autenticación para proteger tus
recursos y evitar eliminaciones no autorizadas.
9. API PUT
Un API PUT es un tipo de solicitud HTTP utilizado para actualizar o reemplazar
un recurso completo en un servidor. La solicitud PUT se utiliza para enviar una
representación completa de un recurso al servidor y actualizarlo según la
información proporcionada.
En Django REST Framework (DRF), puedes implementar un API PUT utilizando
una vista de clase basada en APIView o utilizando un ViewSet. T
Ejemplo de cómo implementar un API PUT utilizando DRF:

from rest_framework.views import APIView


from rest_framework.response import Response

10
from rest_framework import status

class MyPutView(APIView):
def put(self, request, pk):
# Obtener el recurso específico a actualizar
try:
instance = MyModel.objects.get(pk=pk)
except MyModel.DoesNotExist:
return Response({'error': 'Recurso no
encontrado'}, status=status.HTTP_404_NOT_FOUND)

# Obtener los datos enviados en la solicitud PUT


data = request.data

# Validar y procesar los datos


# ...

# Actualizar el recurso
# ...

# Devolver una respuesta apropiada


return Response({'message': 'Recurso actualizado
correctamente'}, status=status.HTTP_200_OK)
En el ejemplo anterior, se define la clase MyPutView como una subclase de
APIView y se implementa el método put(). Dentro de este método, se espera que
se proporcione un parámetro pk que representa la clave primaria del recurso a
actualizar.
Primero, se intenta obtener el recurso específico utilizando la clave primaria
proporcionada. Si el recurso no existe, se devuelve una respuesta con el código
de estado HTTP 404 NOT FOUND indicando que el recurso no fue encontrado.
Luego, puedes acceder a los datos enviados en la solicitud PUT utilizando
request.data. Estos datos representan la nueva representación completa del
recurso que se va a actualizar.

11
Después de obtener los datos, puedes realizar la validación y el procesamiento
necesarios en los datos recibidos. Esto puede incluir la verificación de la
integridad de los datos, la validación de reglas de negocio o cualquier otra lógica
personalizada.
Una vez validados los datos, puedes proceder a actualizar el recurso utilizando
los datos proporcionados y guardar los cambios en la base de datos.
Finalmente, se devuelve una respuesta con el código de estado HTTP 200 OK
para indicar que el recurso ha sido actualizado correctamente. Puedes incluir un
mensaje descriptivo en la respuesta si lo deseas.
Es importante tener en cuenta que en este ejemplo se asume que ya existe un
recurso con la clave primaria proporcionada. Si deseas permitir la creación de un
nuevo recurso en caso de que no exista, puedes modificar la lógica según tus
necesidades específicas. Además, asegúrate de implementar las adecuadas
consideraciones de seguridad y autenticación para proteger tus recursos y evitar
actualizaciones no autorizadas.
10. ENDPOINT
En el contexto de las API, un endpoint se refiere a una URL específica a la cual
puedes enviar una solicitud HTTP para interactuar con un servicio web o una
aplicación. Cada endpoint generalmente representa una acción o una operación
específica que se puede realizar en el servidor.
Ejemplos de endpoints:

• Obtener una lista de usuarios:


• GET /api/users

• Obtener los detalles de un usuario específico:


• GET /api/users/{id}

• Crear un nuevo usuario:


• POST /api/users

• Actualizar los detalles de un usuario existente:


• PUT /api/users/{id}

• Eliminar un usuario:
• DELETE /api/users/{id}

12
En los ejemplos anteriores, /api/users es la ruta base que representa la colección
de usuarios. Los métodos HTTP como GET, POST, PUT y DELETE se utilizan
para indicar la acción que deseas realizar en ese recurso específico.
El parámetro {id} en los ejemplos representa el identificador único de un usuario
específico. Puedes reemplazar {id} con el valor real del identificador al realizar
solicitudes a ese endpoint en particular.
Cada endpoint tiene un propósito y una funcionalidad específica en función de
las necesidades de tu aplicación. Al diseñar tu API, debes definir y mapear tus
endpoints de acuerdo con las operaciones que deseas permitir a los clientes en
tu servicio web o aplicación.

13
1. AUTENTICACION BASICA
La autenticación básica en DRF se basa en el uso de credenciales de usuario,
es decir, un nombre de usuario y una contraseña, que se envían en cada solicitud
HTTP para autenticar al usuario.
Para habilitar la autenticación básica en una vista de DRF, debes seguir los
siguientes pasos:
Importar la clase BasicAuthentication desde el módulo
rest_framework.authentication:
from rest_framework.authentication import
BasicAuthentication

Agregar la clase BasicAuthentication a la lista authentication_classes de la vista


o vista basada en clases que deseas proteger con autenticación básica:
class MyView(APIView):
authentication_classes = [BasicAuthentication]
Opcionalmente, puedes agregar la clase SessionAuthentication a la lista
authentication_classes si también deseas soporte de autenticación basada en
sesiones:
class MyView(APIView):
authentication_classes = [BasicAuthentication,
SessionAuthentication]
Una vez que hayas configurado la autenticación básica, cuando un cliente haga
una solicitud a la vista protegida, DRF verificará las credenciales enviadas en el
encabezado de la solicitud y autenticará al usuario.
from rest_framework.views import APIView
from rest_framework.authentication import
BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

class MyView(APIView):
authentication_classes = [BasicAuthentication]
permission_classes = [IsAuthenticated]

def get(self, request):


# Obtener el usuario autenticado

1
user = request.user

# Resto de la lógica de la vista


...

return Response("Hello, authenticated user!")

En este ejemplo, la clase MyView se asegurará de que el usuario esté


autenticado utilizando la autenticación básica. La clase IsAuthenticated en
permission_classes asegurará que solo los usuarios autenticados puedan
acceder a esta vista.
Recuerda que para usar la autenticación básica, los clientes deben enviar las
credenciales en el encabezado Authorization de la solicitud en el formato "Basic
username:password" codificado en Base64.
Es importante tener en cuenta que la autenticación básica envía las credenciales
en texto plano en cada solicitud, por lo que se recomienda utilizar una conexión
segura (HTTPS) para proteger la información sensible de los usuarios.
2. API Keys
La autenticación con API keys es un método común utilizado para autenticar las
solicitudes a una API. En lugar de utilizar un nombre de usuario y contraseña, se
utiliza una clave de API única asociada a cada usuario o aplicación para
autenticar las solicitudes.
DRF proporciona la clase TokenAuthentication para la autenticación con API
keys. Esta clase utiliza tokens de autenticación generados y asignados a cada
usuario para verificar la autenticidad de las solicitudes.
A continuación, te muestro un ejemplo de uso de la autenticación con API keys
en DRF:
Primero, asegúrate de que la autenticación con tokens esté habilitada en la
configuración de tu proyecto. Agrega la siguiente línea en tu archivo settings.py:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [

'rest_framework.authentication.TokenAuthentication',
],
}
Asegúrate de que cada usuario tenga un token de autenticación asociado.
Puedes generar un token para un usuario específico utilizando el siguiente
código:
2
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User

user = User.objects.get(username='nombre_de_usuario')
token, created = Token.objects.get_or_create(user=user)
Una vez que hayas configurado la autenticación con tokens, puedes usarla en
tus vistas o vistas basadas en clases de la siguiente manera:
from rest_framework.views import APIView
from rest_framework.authentication import
TokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

class MyView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]

def get(self, request):


# Obtener el usuario autenticado
user = request.user

# Resto de la lógica de la vista


...

return Response("Hello, authenticated user!")

En este ejemplo, la clase MyView utiliza la autenticación con tokens mediante la


clase TokenAuthentication. La clase IsAuthenticated en permission_classes
asegurará que solo los usuarios autenticados puedan acceder a esta vista.
Cuando los clientes realicen solicitudes a esta vista, deberán incluir el token de
autenticación en el encabezado de la solicitud. Por ejemplo:

makefile

3
Authorization: Token <token_value>

Cada vez que se reciba una solicitud, DRF verificará la validez del token enviado
y asociará el usuario correspondiente a la solicitud.
Es importante tener en cuenta que debes proteger y mantener seguros los tokens
de autenticación, ya que otorgan acceso a la API en nombre del usuario o
aplicación.
3. Bearer
Bearer Tokens es un método de autenticación basado en tokens utilizado en los
sistemas de API. Estos tokens se utilizan para autenticar y autorizar las
solicitudes a los recursos protegidos en una API. La autenticación basada en
Bearer Tokens se basa en el esquema de autenticación "portador" (Bearer)
definido en el estándar HTTP.
Cuando un cliente desea acceder a un recurso protegido en una API, debe incluir
el token de acceso en el encabezado "Authorization" de la solicitud HTTP. El
token se envía de la siguiente manera:
Authorization: Bearer <token>
El token de acceso puede ser cualquier cadena alfanumérica generada por el
servidor de autenticación. Este token es independiente y no contiene información
adicional sobre el usuario o la sesión. El servidor de la API confía en que el token
de acceso válido enviado en la solicitud es suficiente para autenticar y autorizar
al usuario.
Registro y autenticación del usuario:
Un usuario se registra y proporciona sus credenciales (por ejemplo, nombre de
usuario y contraseña) al servidor de autenticación. El servidor autentica al
usuario y genera un token de acceso.
Emisión del token de acceso:
El servidor de autenticación emite un token de acceso al cliente después de la
autenticación exitosa. Este token se devuelve al cliente y se almacena
localmente.
Inclusión del token de acceso en las solicitudes:
Cuando el cliente desea acceder a un recurso protegido en la API, incluye el
token de acceso en el encabezado "Authorization" de la solicitud HTTP como se
mencionó anteriormente.
Validación del token de acceso:
El servidor de la API recibe la solicitud y valida el token de acceso. Si el token es
válido, se permite el acceso al recurso protegido y se devuelve la respuesta
correspondiente.

4
Es importante tener en cuenta que los Bearer Tokens no proporcionan
información adicional en el token en sí mismo, como la identidad del usuario. La
validez del token se verifica en cada solicitud y el servidor de la API puede
necesitar consultar una fuente de almacenamiento adicional para obtener los
detalles del usuario y autorizar la acción.

4. JSON Web Tokens


JSON Web Tokens (JWT) es un estándar abierto (RFC 7519) que permite la
transferencia segura de información entre partes como objetos JSON. En DRF,
JWT se utiliza como un método de autenticación y autorización popular debido a
su portabilidad, seguridad y capacidad de autenticación sin estado.

DRF no proporciona JWT de forma nativa, pero se puede integrar fácilmente


mediante el uso de bibliotecas externas como djangorestframework_simplejwt,
djangorestframework-jwt, pyjwt, entre otros.
Instalación:
Asegúrate de tener la biblioteca djangorestframework_simplejwt instalada en tu
entorno de desarrollo:
pip install djangorestframework_simplejwt

Configuración:
Agrega 'rest_framework_simplejwt.authentication.JWTAuthentication' en la lista
de clases de autenticación de DRF en tu archivo de configuración (settings.py):
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [

'rest_framework_simplejwt.authentication.JWTAuthentication'
,
# otras clases de autenticación...
],
}

Generación y emisión del JWT:


Puedes generar y emitir un JWT cuando un usuario se autentique correctamente.
Aquí tienes un ejemplo utilizando vistas basadas en clases y serializadores de
DRF:
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.views import APIView

5
from rest_framework.response import Response
from .serializers import UserSerializer

class TokenObtainView(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
refresh = RefreshToken.for_user(user)

return Response({
'refresh': str(refresh),
'access': str(refresh.access_token),
})

En este ejemplo, cuando un usuario proporciona sus credenciales y son válidas,


se genera un JWT utilizando la clase RefreshToken de
rest_framework_simplejwt.tokens. El token de actualización (refresh) y el token
de acceso (access) se devuelven en la respuesta.
Protección de vistas:
Puedes proteger tus vistas de Django utilizando el decorador @api_view y
especificando la autenticación requerida en tus vistas. Por ejemplo:
from rest_framework.decorators import api_view,
permission_classes
from rest_framework.permissions import IsAuthenticated

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def protected_view(request):
# Tu lógica de vista protegida aquí...
En este ejemplo, la vista protected_view está protegida y solo se permitirá el
acceso a los clientes autenticados mediante JWT.
Validación y decodificación del JWT:

6
El JWT se valida y decodifica automáticamente por JWTAuthentication en DRF.
Puedes acceder a los datos del usuario autenticado utilizando el objeto
request.user en tus vistas.
5. OAUTH
OAuth (Open Authorization) es un protocolo de autorización estándar que
permite a las aplicaciones de terceros obtener acceso limitado a los recursos
protegidos de un usuario en un servicio en línea sin necesidad de conocer sus
credenciales de inicio de sesión. OAuth se utiliza comúnmente para permitir que
los usuarios autoricen a las aplicaciones de terceros a acceder a sus cuentas y
recursos en servicios como Google, Facebook, Twitter, etc.
Configuración de proveedores de OAuth:
Antes de utilizar OAuth en DRF, debes configurar los proveedores de OAuth,
como Google, Facebook o cualquier otro servicio que desees utilizar para la
autenticación y autorización. Cada proveedor tiene su propia documentación y
pasos para configurar OAuth. Por ejemplo, para Google, debes crear una
aplicación en el Developer Console de Google y obtener las credenciales (Client
ID y Client Secret).
Integración de proveedores de OAuth en DRF:
Una vez que hayas configurado los proveedores de OAuth, debes integrarlos en
DRF utilizando una biblioteca de OAuth. Hay varias opciones disponibles, como
django-oauth-toolkit, django-allauth, python-social-auth, entre otras. Estas
bibliotecas facilitan la integración de proveedores de OAuth en tu aplicación DRF.
Flujo de autorización de OAuth:
El flujo de autorización de OAuth implica varios pasos, que incluyen la redirección
del usuario al proveedor de OAuth para autorizar la aplicación y recibir un código
de autorización. Luego, este código se intercambia por un token de acceso que
se utilizará para acceder a los recursos protegidos en nombre del usuario.
Implementación en DRF:
Una vez que hayas configurado los proveedores de OAuth y elegido una
biblioteca de OAuth, deberás implementar las vistas y rutas en tu aplicación DRF
para manejar los flujos de autorización y la obtención de tokens de acceso. Esto
implica definir vistas de inicio de sesión, vistas de redirección y vistas de
intercambio de código por token de acceso.
Protección de vistas:
Para proteger tus vistas de DRF utilizando OAuth, puedes utilizar el decorador
@api_view y especificar los scopes o permisos requeridos para acceder a cada
vista. De esta manera, solo los usuarios autenticados y autorizados mediante
OAuth podrán acceder a las vistas protegidas.

7
Ejemplo con allauth
Configuración:
Primero, asegúrate de tener instaladas las bibliotecas necesarias en tu entorno
de desarrollo:
pip install django-allauth

Configura django-allauth:
Agrega 'allauth' y 'allauth.account' a la lista de aplicaciones en tu archivo de
configuración (settings.py):
INSTALLED_APPS = [
# otras aplicaciones...
'allauth',
'allauth.account',
]

Además, asegúrate de configurar la URL de redirección después de la


autorización en tu archivo de configuración:
LOGIN_REDIRECT_URL = '/accounts/profile/'

Configura las URLs:


Añade las URLs necesarias en tu archivo de URL (urls.py) para las vistas de
autenticación proporcionadas por django-allauth:
from django.urls import include, path

urlpatterns = [
# otras URLs...
path('accounts/', include('allauth.urls')),
]
Protección de vistas:
Puedes proteger tus vistas de DRF utilizando el decorador @api_view y
especificando los permisos requeridos. Por ejemplo:
from rest_framework.decorators import api_view,
permission_classes
from rest_framework.permissions import IsAuthenticated

@api_view(['GET'])

8
@permission_classes([IsAuthenticated])
def protected_view(request):
# Tu lógica de vista protegida aquí...

En este ejemplo, la vista protected_view está protegida y solo se permitirá el


acceso a los usuarios autenticados mediante OAuth.
Configura proveedores de OAuth:
En la configuración de django-allauth, puedes agregar proveedores de OAuth
como Google, Facebook, Twitter, etc. Para cada proveedor, deberás obtener las
claves de API correspondientes y configurarlas en tu archivo de configuración.
Por ejemplo, para Google:
SOCIALACCOUNT_PROVIDERS = {
'google': {
'SCOPE': ['profile', 'email'],
'AUTH_PARAMS': {'access_type': 'online'},
}
}

Implementa vistas y rutas:


Puedes utilizar las vistas proporcionadas por django-allauth para el flujo de
autorización de OAuth. Por ejemplo, una vista de inicio de sesión:
from allauth.socialaccount.providers.oauth2.views import (
OAuth2Adapter,
OAuth2LoginView,
)

class GoogleOAuth2Adapter(OAuth2Adapter):
provider_id = 'google'
access_token_url =
'https://accounts.google.com/o/oauth2/token'
authorize_url =
'https://accounts.google.com/o/oauth2/auth'
profile_url =
'https://www.googleapis.com/oauth2/v1/userinfo'

9
google_oauth2_login =
OAuth2LoginView.adapter_view(GoogleOAuth2Adapter)

En este ejemplo, la vista google_oauth2_login es la vista de inicio de sesión para


Google OAuth2. Puedes configurar vistas similares para otros proveedores de
OAuth que desees utilizar.
Recuerda que este es solo un ejemplo básico para ilustrar la implementación de
OAuth en DRF utilizando django-allauth. La configuración y los detalles pueden
variar dependiendo de tus requisitos y los proveedores de OAuth que elijas.

Método de Nivel de Nivel de Seguridad Casos de Uso Frecuentes


Autenticación Complejidad de
Implementación

Autenticación Básica Bajo Bajo API privadas internas

API Keys Bajo Medio Acceso a terceros

Bearer Tokens Medio Medio API de usuarios

JSON Web Tokens Medio a Alto Alto Microservicios


(JWT)

OAuth 2.0 Alto Alto Acceso a recursos de terceros

10
1. RELACIONES
Una relación de API se refiere a la conexión o interacción entre diferentes
recursos o endpoints en una API. En el contexto de Django Rest Framework
(DRF), una relación de API se establece cuando hay una dependencia o
asociación entre diferentes recursos.
En DRF, las relaciones de API se pueden establecer utilizando campos
especiales en los serializers, como ForeignKeyField o ManyToManyField, que
representan las relaciones entre los modelos de Django. Estos campos permiten
definir y gestionar la conexión entre los diferentes objetos relacionados en la API.

Una relación de API puede tener diferentes formas, como:

• Relación uno a uno (One-to-One): Se establece cuando un objeto solo


puede estar relacionado con otro objeto. Por ejemplo, una relación entre
un usuario y su perfil de usuario.

• Relación uno a muchos (One-to-Many): Se establece cuando un objeto


puede estar relacionado con varios objetos. Por ejemplo, una relación
entre un autor y sus publicaciones.

• Relación muchos a muchos (Many-to-Many): Se establece cuando varios


objetos pueden estar relacionados entre sí. Por ejemplo, una relación
entre dos modelos como "etiquetas" y "publicaciones" en un sistema de
blogs, donde una publicación puede tener múltiples etiquetas y una
etiqueta puede estar asociada a varias publicaciones.

Estas relaciones de API permiten obtener, crear, actualizar y eliminar objetos


relacionados a través de endpoints específicos. Al establecer correctamente las
relaciones de API, puedes diseñar y desarrollar una API que maneje de manera
eficiente la interacción y dependencia entre diferentes recursos.
En Django Rest Framework (DRF), el manejo de relaciones en una API se realiza
utilizando el concepto de serializers y viewsets.
Serializers:
Los serializers en DRF son clases que permiten definir cómo los modelos de
Django deben ser serializados y deserializados. Para manejar relaciones, los
serializers proporcionan diferentes tipos de campos:

1
• PrimaryKeyRelatedField: Representa una relación de clave primaria
(PrimaryKey) entre modelos. Este campo muestra el ID de la relación en
la representación JSON.
• StringRelatedField: Representa una relación de clave foránea
(ForeignKey) entre modelos, pero en lugar de mostrar el ID de la relación,
muestra una representación en cadena del objeto relacionado.
• SlugRelatedField: Similar al StringRelatedField, pero en lugar de usar el
ID de la relación, utiliza un campo de "slug" (una versión amigable para
URL) del objeto relacionado.
• HyperlinkedRelatedField: Representa una relación de clave foránea
(ForeignKey) entre modelos utilizando URLs. Muestra enlaces a los
detalles del objeto relacionado.
• SerializerMethodField: Permite definir un método personalizado en el
serializer que se utilizará para obtener la representación del campo
relacionado.

Viewsets:
Los viewsets en DRF son clases que proporcionan una interfaz para interactuar
con los modelos de Django. Aquí tienes algunos detalles adicionales sobre su
uso con relaciones:
• Nested relationships: Los viewsets permiten establecer relaciones
anidadas en los endpoints de la API. Esto significa que puedes acceder a
objetos relacionados desde un objeto principal y realizar operaciones
CRUD en ellos.
• Override methods: Los viewsets proporcionan métodos como list(),
create(), retrieve(), update(), partial_update() y destroy() para manejar
diferentes operaciones en los objetos relacionados.
• URL routing: DRF genera automáticamente rutas de URL para los
viewsets, lo que te permite acceder a diferentes operaciones en objetos
relacionados a través de URLs específicas.

Al utilizar serializers y viewsets en conjunto, puedes definir cómo se serializan y


deserializan los objetos relacionados en tu API. Además, los viewsets te permiten
realizar operaciones CRUD en los objetos relacionados de manera coherente y
eficiente, proporcionando una forma robusta de manejar relaciones en tu API con
Django Rest Framework.
2. PRIMARY KEY
El campo PrimaryKeyRelatedField es utilizado para establecer relaciones de
clave primaria (PrimaryKey) entre diferentes modelos en DRF. Este campo
representa la relación utilizando el ID de la clave primaria del objeto relacionado.

2
Uso en el Serializer:
En el serializer, se define el campo PrimaryKeyRelatedField para representar la
relación. Aquí tienes un ejemplo de cómo se ve en código:
from rest_framework import serializers
from .models import Autor, Libro

class LibroSerializer(serializers.ModelSerializer):
autor =
serializers.PrimaryKeyRelatedField(queryset=Autor.objects.a
ll())

class Meta:
model = Libro
fields = ['id', 'titulo', 'autor']

En este ejemplo, el campo 'autor' en el serializer del modelo 'Libro' se establece


como PrimaryKeyRelatedField. Utilizamos el argumento 'queryset' para
especificar el conjunto de objetos de la clase 'Autor' disponibles para la relación.
Ejemplo en la API:
Supongamos que tenemos los modelos 'Autor' y 'Libro', donde un libro está
relacionado con un autor a través de la clave primaria. Aquí tienes un ejemplo de
cómo crear un libro relacionado con un autor existente utilizando el campo
PrimaryKeyRelatedField:
POST /api/libros/

{
"titulo": "El Gran Gatsby",
"autor": 1
}

En este ejemplo, estamos creando un nuevo libro con el título "El Gran Gatsby"
y estableciendo la relación con el autor cuyo ID es 1. El campo 'autor' en el objeto
JSON representa la clave primaria del autor relacionado.
La relación a través del campo PrimaryKeyRelatedField permite establecer y
manipular las relaciones utilizando el ID de la clave primaria del objeto
relacionado. Esto proporciona una forma sencilla de representar y gestionar
relaciones en tu API utilizando Django Rest Framework.

3
3. STRING RELATED FIELD
El campo StringRelatedField se utiliza para representar relaciones a través de
campos de texto, como cadenas de caracteres. Este campo es útil cuando
deseas mostrar o manipular la representación legible de un objeto relacionado
en lugar de su ID o clave primaria.
Uso en el Serializer:
En el serializer, se define el campo StringRelatedField para representar la
relación. Aquí tienes un ejemplo de cómo se ve en código:
from rest_framework import serializers
from .models import Autor, Libro

class LibroSerializer(serializers.ModelSerializer):
autor = serializers.StringRelatedField()

class Meta:
model = Libro
fields = ['id', 'titulo', 'autor']

En este ejemplo, el campo 'autor' en el serializer del modelo 'Libro' se establece


como StringRelatedField. Esto mostrará la representación en formato de cadena
del autor relacionado en lugar de su ID.
Ejemplo en la API:
Supongamos que tenemos los modelos 'Autor' y 'Libro', donde un libro está
relacionado con un autor a través de una relación ForeignKey. Aquí tienes un
ejemplo de cómo se vería la respuesta de la API:
GET /api/libros/1
{
"id": 1,
"titulo": "El Gran Gatsby",
"autor": "F. Scott Fitzgerald"
}

En este ejemplo, estamos obteniendo un libro con el ID 1 y la respuesta incluye


la representación en formato de cadena del autor relacionado.

4
La relación a través del campo StringRelatedField permite mostrar la
representación legible de un objeto relacionado en lugar de su ID o clave
primaria. Esto es útil cuando deseas proporcionar información más descriptiva
en tu API.
4. SLUG RELATED FIELD
El campo SlugRelatedField se utiliza para establecer relaciones utilizando un
campo slug en lugar de la clave primaria. Un campo slug es una versión
simplificada de un campo de texto que generalmente se utiliza para crear URL
legibles por humanos.
Uso en el Serializer:
En el serializer, se define el campo SlugRelatedField para representar la relación.
Aquí tienes un ejemplo de cómo se ve en código:
from rest_framework import serializers
from .models import Autor, Libro

class LibroSerializer(serializers.ModelSerializer):
autor =
serializers.SlugRelatedField(slug_field='nombre',
queryset=Autor.objects.all())

class Meta:
model = Libro
fields = ['id', 'titulo', 'autor']

En este ejemplo, el campo 'autor' en el serializer del modelo 'Libro' se establece


como SlugRelatedField. Utilizamos el argumento 'slug_field' para especificar el
campo slug en el modelo relacionado. Además, especificamos el conjunto de
objetos de la clase 'Autor' disponibles para la relación.
Ejemplo en la API:
Supongamos que tenemos los modelos 'Autor' y 'Libro', donde un libro está
relacionado con un autor a través de un campo slug 'nombre'
GET /api/libros/1

{
"id": 1,
"titulo": "El Gran Gatsby",

5
"autor": "f-scott-fitzgerald"
}

En este ejemplo, estamos obteniendo un libro con el ID 1 y la respuesta incluye


el campo slug del autor relacionado.
La relación a través del campo SlugRelatedField permite establecer relaciones
utilizando campos slug en lugar de la clave primaria. Esto es útil cuando deseas
utilizar valores más descriptivos en tus relaciones y mostrar información legible
por humanos en tu API.

5. Hyperlinked Related Field


El campo HyperlinkedRelatedField se utiliza para establecer relaciones
utilizando enlaces hipermedia. En lugar de representar la relación como un
campo de clave primaria o algún otro valor identificador, este campo representa
la relación como una URL que enlaza al recurso relacionado.
Uso en el Serializer:
En el serializer, se define el campo HyperlinkedRelatedField para representar la
relación. Aquí tienes un ejemplo de cómo se ve en código:
from rest_framework import serializers
from .models import Autor, Libro

class LibroSerializer(serializers.ModelSerializer):
autor = serializers.HyperlinkedRelatedField(
view_name='autor-detail',
queryset=Autor.objects.all()
)

class Meta:
model = Libro
fields = ['id', 'titulo', 'autor']

En este ejemplo, el campo 'autor' en el serializer del modelo 'Libro' se establece


como HyperlinkedRelatedField. Utilizamos el argumento 'view_name' para
especificar el nombre de la vista asociada al modelo 'Autor'. Además,
especificamos el conjunto de objetos de la clase 'Autor' disponibles para la
relación.

6
Ejemplo en la API:
Supongamos que tenemos los modelos 'Autor' y 'Libro', donde un libro está
relacionado con un autor a través de una URL que enlaza al recurso del autor.
GET /api/libros/1

{
"id": 1,
"titulo": "El Gran Gatsby",
"autor": "http://localhost/api/autores/1/"
}
En este ejemplo, estamos obteniendo un libro con el ID 1 y la respuesta incluye
la URL del recurso del autor relacionado.
La relación a través del campo HyperlinkedRelatedField permite establecer
relaciones utilizando enlaces hipermedia en lugar de identificadores de clave
primaria. Esto facilita la navegación y exploración de la API al proporcionar
enlaces a recursos relacionados.

6. Serializer Method Field


El campo SerializerMethodField se utiliza cuando necesitas representar una
relación personalizada en tu serializer. En lugar de utilizar un campo predefinido,
puedes definir un método en tu serializer que calcule o extraiga el valor de la
relación.
Uso en el Serializer:
En el serializer, se define un método que representa la relación personalizada y
se asigna al campo SerializerMethodField.
from rest_framework import serializers
from .models import Autor, Libro

class LibroSerializer(serializers.ModelSerializer):
autor_nombre = serializers.SerializerMethodField()

class Meta:
model = Libro
fields = ['id', 'titulo', 'autor_nombre']

7
def get_autor_nombre(self, obj):
return obj.autor.nombre

En este ejemplo, hemos definido un método llamado 'get_autor_nombre' que


extrae el nombre del autor asociado a un libro. Luego, asignamos este método
al campo 'autor_nombre' que es un SerializerMethodField en el serializer del
modelo 'Libro'.
Ejemplo en la API:
Supongamos que tenemos los modelos 'Autor' y 'Libro', donde un libro está
relacionado con un autor a través de una relación ForeignKey.
GET /api/libros/1
{
"id": 1,
"titulo": "El Gran Gatsby",
"autor_nombre": "F. Scott Fitzgerald"
}

En este ejemplo, estamos obteniendo un libro con el ID 1 y la respuesta incluye


el nombre del autor obtenido a través del método personalizado
'get_autor_nombre'.
La relación a través del campo SerializerMethodField te brinda flexibilidad para
calcular o extraer valores de la relación de manera personalizada. Puedes
realizar operaciones adicionales, acceder a otros campos relacionados o aplicar
lógica específica según tus necesidades.

7. Relaciones anidadas
Las relaciones anidadas permiten representar y gestionar relaciones complejas
entre modelos relacionados en tus ViewSets. Esto te permite incluir y manipular
objetos relacionados dentro de la respuesta de tu API
Uso en el ViewSet:
En el ViewSet, puedes definir una relación anidada utilizando el campo
relacionado correspondiente (ForeignKey, OneToOneField, ManyToManyField) y
configurando el serializer relacionado para esa relación.
from rest_framework import serializers, viewsets
from .models import Autor, Libro

8
class LibroSerializer(serializers.ModelSerializer):
class Meta:
model = Libro
fields = ['id', 'titulo']

class AutorSerializer(serializers.ModelSerializer):
libros = LibroSerializer(many=True, read_only=True)

class Meta:
model = Autor
fields = ['id', 'nombre', 'libros']

class AutorViewSet(viewsets.ModelViewSet):
queryset = Autor.objects.all()
serializer_class = AutorSerializer

En este ejemplo, hemos definido dos serializers: 'LibroSerializer' y


'AutorSerializer'. En 'AutorSerializer', hemos incluido una relación anidada
utilizando el campo 'libros' que representa una relación de uno a muchos con el
modelo 'Libro'. El campo 'libros' utiliza el 'LibroSerializer' para representar los
objetos relacionados.
Ejemplo en la API:
Supongamos que tenemos los modelos 'Autor' y 'Libro', donde un autor puede
tener varios libros asociados.
GET /api/autores/1

{
"id": 1,
"nombre": "J.R.R. Tolkien",
"libros": [
{
"id": 1,
"titulo": "El Señor de los Anillos"

9
},
{
"id": 2,
"titulo": "El Hobbit"
}
]
}

En este ejemplo, estamos obteniendo un autor con el ID 1 y la respuesta incluye


una lista de los libros asociados a ese autor. Los libros están representados
utilizando el 'LibroSerializer'.
El uso de relaciones anidadas en los ViewSets te permite incluir objetos
relacionados dentro de la respuesta de tu API de manera sencilla. Esto facilita el
acceso y la manipulación de objetos relacionados sin tener que realizar consultas
adicionales a la base de datos.

10

También podría gustarte