Siguiendo con la serie de tutoriales para consumir distintas bases de datos hoy veremos cómo conectarnos a una base de datos de MongoDB y hacer todas las operaciones para crear, leer, actualizar y eliminar desde Python.
El módulo que usaremos será PyMongo; el cual está disponible para instalarse por medio de Python y que nos permite conectarnos a MongoDB, obtener bases de datos, colecciones y todo lo relacionado a ello.
Al finalizar podremos gestionar una colección de productos de una tienda.
Asegúrate de tener instalado Python y PIP, así como MongoDB. Igualmente te recomiendo instalar un administrador de MongoDB: Robo 3T. Finalmente, crea algunos usuarios para gestionar tu instalación de MongoDB; por seguridad.
Otros posts que tal vez quieras leer:
Una vez que tengas instalado pip, ejecuta lo siguiente en tu terminal:
python -m pip install pymongo
Espera a que se termine de instalar y con eso tenemos
Con los ejemplos que iremos viendo, es muy útil una herramienta que nos permita confirmar si efectivamente nuestros cambios se están haciendo en la base de datos.
Por ejemplo, si programamos el método para insertar datos, ¿cómo sabemos si se insertaron, si todavía no hemos programado la parte para listarlos?
Para eso es que usamos la herramienta, ya que con ella puedes ir viendo cómo está tu base de datos. Recuerda que dejé un link a la instalación allá arriba.
Para crear una nueva conexión, instanciamos a MongoClient
pasándole las credenciales y los datos necesarios como el host, puerto y nombre de la base de datos. Hay otras maneras, pero esta es la que recomiendo porque nos permite cambiar fácilmente cualquier dato.
Todo eso podemos encerrarlo en una función como la que se ve a continuación:
def obtener_bd():
host = "localhost"
puerto = "27017"
usuario = "parzibyte"
palabra_secreta = "hunter2"
base_de_datos = "tienda"
cliente = MongoClient("mongodb://{}:{}@{}:{}".format(usuario, palabra_secreta, host, puerto))
return cliente[base_de_datos]
Por cierto, en mi caso me conecto a la base de datos tienda (que tiene la colección productos), pero es para ejemplificar.
Cuando conectamos a PHP con MongoDB usamos rawurlencode para codificar el usuario y contraseña para que fueran seguros al viajar como una URL, es decir, codificar caracteres especiales como /
o @
, si tu usuario o contraseña son así, entonces primero codifícalos. Importa el módulo
import urllib.parse
Para luego usar a quote:
pass = urllib.parse.quote("La contraseña con caracteres complejos")
Y listo, no lo incluí en el tutorial porque sería más confuso y largo. No olvides hacer lo mismo con el nombre de usuario.
Vamos a usar una clase para simplificar las cosas. Tranquilo, no es Java y su obligación de la POO; es una simple clase que representa a un producto:
class Producto:
def __init__(self, nombre, precio, cantidad):
self.nombre = nombre
self.precio = precio
self.cantidad = cantidad
Esto nos permitirá crear objetos de tipo Producto
para pasarlos a los siguientes métodos de insertar y actualizar. No es obligatorio, pero así lo haremos.
Comencemos por insertar datos; de nuevo lo digo, lo encerramos en una función que recibe un objeto de tipo producto.
Para insertar un dato, primero obtenemos la colección que se encuentra dentro de nuestra base de datos, y llamamos al método insert_one
.
A ese método le pasamos un diccionario con las claves y valores que queremos insertar.
def insertar(producto):
base_de_datos = obtener_bd()
productos = base_de_datos.productos
return productos.insert_one({
"nombre": producto.nombre,
"precio": producto.precio,
"cantidad": producto.cantidad,
}).inserted_id
Lo que devuelve nuestra función es el id insertado; no estamos obligados a hacerlo pero permite saber si realmente se insertó o no.
Para esto, las colecciones nos dan un método o función llamada find
, así como se hace normalmente en la CLI de MongoDB.
Si no le pasamos un criterio de búsqueda, devolverá todo lo existente. Más tarde, a esto podemos iterarlo con un ciclo foreach, pero primero veamos a la función:
def obtener():
base_de_datos = obtener_bd()
return base_de_datos.productos.find()
Cuando llamamos al método obtener
, podemos iterar los productos. Cabe mencionar que accedemos a sus propiedades a través de producto[clave]
, por ejemplo producto["precio"]
en lugar de producto.precio
.
Para actualizar un valor, llamamos al método update_one
que recibe dos argumentos: el criterio de búsqueda (es decir, la condición que deben cumplir los datos para que se actualicen) y el nuevo valor.
El código queda así:
def actualizar(id, producto):
base_de_datos = obtener_bd()
resultado = base_de_datos.productos.update_one(
{
'_id': ObjectId(id)
},
{
'$set': {
"nombre": producto.nombre,
"precio": producto.precio,
"cantidad": producto.cantidad,
}
})
return resultado.modified_count
Recibe el id del producto que se va a actualizar, y un producto que tiene los nuevos datos, o sea, los que se pondrán al actualizar.
Lo que regresa la función es el número de documentos actualizados; si no cambiamos ningún valor entonces devolverá cero, porque no hubo cambios. Para saber por qué usamos ObjectId
o $set
sigue leyendo.
Aquí hay que ver algo muy importante, y es que como segundo argumento recibe el documento que será el remplazo del anterior. Si solamente queremos actualizar algunos datos, usamos el selector $set
para establecer las propiedades necesarias, en lugar de remplazar todo el documento.
Al usar $set
, si no indicamos una nueva propiedad o nuevo valor, los demás valores se quedan intactos. Si quieres remplazar el documento, entonces simplemente manda el diccionario en lugar de usar un selector de tipo $set
.
Aunque el ID es una cadena aleatoria, para hacer búsquedas a partir del mismo, debemos crear un objeto de tipo ObjectId, pasándole a la cadena que tiene el id como argumento. Esto es necesario siempre que filtremos por ID, ya sea para eliminar, actualizar, buscar o listar.
Ahora veamos el método que elimina, es más simple pues sólo recibe un id del producto que vamos a eliminar. Queda así:
def eliminar(id):
base_de_datos = obtener_bd()
resultado = base_de_datos.productos.delete_one(
{
'_id': ObjectId(id)
})
return resultado.deleted_count
Usamos de nuevo el ObjectId
para el criterio de selección. Lo que devuelve la función es el número de documentos eliminados.
Para ejemplificar todo y poner todo junto de una manera funcional, podemos crear un menú que se imprima por consola, lea la elección del usuario y dependiendo de ello inserte uno, actualice, elimine o consulte.
Aquí puedes leer sobre print e input en Python. Todo el código (recuerda que aparte está la clase, que vive en un archivo llamado producto.py y que tiene el código que está más arriba) queda de la siguiente manera:
from pymongo import MongoClient # El cliente de MongoDB
from producto import Producto # La clase Producto
from bson.objectid import ObjectId # Para crear ObjectId, porque _id como cadena no funciona
def obtener_bd():
host = "localhost"
puerto = "27017"
usuario = "parzibyte"
palabra_secreta = "hunter2"
base_de_datos = "tienda"
cliente = MongoClient("mongodb://{}:{}@{}:{}".format(usuario, palabra_secreta, host, puerto))
return cliente[base_de_datos]
def insertar(producto):
base_de_datos = obtener_bd()
productos = base_de_datos.productos
return productos.insert_one({
"nombre": producto.nombre,
"precio": producto.precio,
"cantidad": producto.cantidad,
}).inserted_id
def obtener():
base_de_datos = obtener_bd()
return base_de_datos.productos.find()
def actualizar(id, producto):
base_de_datos = obtener_bd()
resultado = base_de_datos.productos.update_one(
{
'_id': ObjectId(id)
},
{
'$set': {
"nombre": producto.nombre,
"precio": producto.precio,
"cantidad": producto.cantidad,
}
})
return resultado.modified_count
def eliminar(id):
base_de_datos = obtener_bd()
resultado = base_de_datos.productos.delete_one(
{
'_id': ObjectId(id)
})
return resultado.deleted_count
creditos = """==========================================================
CRUD de MongoDB y Python
__ __ __
.-----.---.-.----.-----|__| |--.--.--| |_.-----.
| _ | _ | _|-- __| | _ | | | _| -__|
| __|___._|__| |_____|__|_____|___ |____|_____|
|__| |_____|
=========================================================="""
menu = """Bienvenido a la tienda.
1 - Insertar producto
2 - Ver todos
3 - Actualizar
4 - Eliminar
5 - Salir
"""
eleccion = None
print(creditos)
while eleccion is not 5:
print(menu)
eleccion = int(input("Elige: "))
if eleccion is 1:
print("Insertar")
nombre = input("Nombre del producto: ")
precio = float(input("Precio del producto: "))
cantidad = float(input("Cantidad del producto: "))
producto = Producto(nombre, precio, cantidad)
id = insertar(producto)
print("El id del producto insertado es: ", id)
elif eleccion is 2:
print("Obteniendo productos...")
for producto in obtener():
print("=================")
print("Id: ", producto["_id"])
print("Nombre: ", producto["nombre"])
print("Precio: ", producto["precio"])
print("Cantidad: ", producto["cantidad"])
elif eleccion is 3:
print("Actualizar")
id = input("Dime el id: ")
nombre = input("Nuevo nombre del producto: ")
precio = float(input("Nuevo precio del producto: "))
cantidad = float(input("Nueva cantidad del producto: "))
producto = Producto(nombre, precio, cantidad)
productos_actualizados = actualizar(id, producto)
print("Número de productos actualizados: ", productos_actualizados)
elif eleccion is 4:
print("Eliminar")
id = input("Dime el id: ")
productos_eliminados = eliminar(id)
print("Número de productos eliminados: ", productos_eliminados)
Recuerda que es un simple ejemplo, no es para usarse en la vida real.
Te invito a leer la documentación oficial para indagar más sobre el tema de Python y MongoDB:
https://api.mongodb.com/python/current/
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…
Esta web usa cookies.
Ver comentarios