python

CRUD (create, read, update, delete) en Python y MongoDB

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.

CRUD de MongoDB y Python con PyMongo

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.

Requisitos y recomendaciones

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:

Instalar librería

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

¿Por qué usar Robo 3T?

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.

Conectar a MongoDB desde Python: obtener base de datos

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.

Una nota sobre el usuario y la contraseña

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.

La clase

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.

Insertar o crear datos en MongoDB desde Python 3

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.

Obtener datos de una colección de MongoDB a través de Python 3

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.

Actualizar dato de MongoDB con PyMongo

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.

¿Establecer o remplazar?

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.

El ObjectId

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.

Eliminar datos de una colección en MongoDB

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.

Ejemplo de uso con PyMongo y MongoDB

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.

Conclusión

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/

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

Entradas recientes

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

3 días hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

3 días hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

3 días hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

3 días hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

3 días hace

Solución: Apache – Server unable to read htaccess file

Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…

4 días hace

Esta web usa cookies.