Dungeon of Bits
Aprendiendo informática.
Dungeon of Bits

Conectar con una base de datos PostgreSQL desde Python

En este tutorial vamos a utilizar Python para conectar con una base de datos PostgreSQL.

Python

Requisitos:

Para realizar esta práctica tan solo necesitamos un sistema con Python instalado. En nuestro caso vamos a utilizar un equipo con Ubuntu 22.04 LTS y Pycharm como framework de trabajo.

Para instalar Pycharm desde Ubuntu tan solo necesitamos teclear la instrucción:

sudo snap install pycharm-community --classic

También necesitaremos la librería Psycopg2 de Python para conectar con la BBDD, la cual instalaremos en el siguiente paso.

Crear proyecto en Pycharm:

Al arrancar Pycharm podemos crear un nuevo proyecto, el programa nos dejará escoger el nombre del proyecto y el directorio donde estarán los ficheros, además nos dejará escoger la versión de Python que utilizaremos, en este caso será la 3.10 y el entorno virtual, usaremos Venv.

Conectar a PostgreSQL desde Python

Instalar Psycopg2:

Para comunicarnos desde Python con PostgreSQL necesitamos la librería Psycopg2, la instalaremos dentro del entorno virtual de nuestro proyecto, para eso iremos a un Terminal hasta el directorio del proyecto.

Una vez en el directorio del proyecto activamos el entorno virtual y después instalamos la librería con Pip:

. venv/bin/activate
pip install psycopg2-binary

Conectar a PostgreSQL desde Python

Conectar con la base de datos:

Crear fichero con los datos de acceso:

Para conectar con la base de datos PostgreSQL el módulo Psycopg2 utiliza la función connect, esta función necesita conocer una serie de información como son el nombre de la base de datos, la localización de la misma y los datos del usuario que va a acceder a ella.

Imaginemos que vamos a conectar con la base de datos Practica1 de la máquina local con el usuario estudiante que tiene la contraseña 3st4d14nt3, usaríamos la siguiente sentencia:

conn = psycopg2.connect(
    host="localhost",
    database="practica1",
    user="estudiante",
    password="3stud14nt3")

Si no se menciona el puerto port, será 5432 por defecto.

Esto tiene varios problemas, el primero de todos es que cualquiera puede acceder a los datos de acceso a la base de datos...

Una solución es guardar los datos sensibles de conexión de la Base de datos en un fichero, al cual llamaremos data.ini, dentro del cual estarán los datos almacenados.

El fichero data.ini quedaría así:

[postgresql]
host=localhost
database=practica1
user=estudiante
password=3stud14nt3

Si se cambiasen los datos de la base de datos en cualquier momento solo habría que cambiar este fichero, el código del programa no cambiaría para nada.

IMPORTANTE Este fichero no debe distribuirse junto al proyecto, si se usa un sistema de gestión de versiones como git es importante no incluir este fichero, para eso se puede incluir dentro del fichero .gitignore.

Crear un fichero con la función para leer los datos del fichero data.ini:

Ahora creamos un fichero llamado config.py que servirá para leer los parámetros del fichero data.ini, el fichero quedará así:

from configparser import ConfigParser


def config(filename='data.ini', section='postgresql'):
    parser = ConfigParser()
    parser.read(filename)

    db = {}
    if parser.has_section(section):
        params = parser.items(section)
        for param in params:
            db[param[0]] = param[1]
    else:
        raise Exception('Sección {0} no encontrada en el {1} fichero'.format(section, filename))

    return db

Y la estructura de archivos del proyecto quedará así:

Conectar a PostgreSQL desde Python

Conectar con la base de datos:

Ahora en nuestro fichero main.py vamos a crear un pequeño programa para conectar con la base de datos el cual solamente nos mostrará la versión del servidor PostgreSQL:

import psycopg2
from config import config


def connect():
    conn = None
    try:
        # Leemos los parámetros de conexión
        params = config()

        # Conectamos con el servidor PostgreSQL
        print('Conectando con PostgreSQL...')
        conn = psycopg2.connect(**params)

        # creamos un cursor
        cur = conn.cursor()

        # Ejecutamos una sentencia SQL
        print('PostgreSQL database version:')
        cur.execute('SELECT version()')

        # Mostramos la versión de PostgreSQL que hemos solicitado con la sentencia anterior
        db_version = cur.fetchone()
        print(db_version)

        # Cerramos la comunicación con PostgreSQL
        cur.close()
    except (Exception, psycopg2.DatabaseError) as error:
        print(error)
    finally:
        if conn is not None:
            conn.close()
            print('Database connection closed.')


if __name__ == '__main__':
    connect()

El resultado del programa será algo similar a la imagen:

Conectar a PostgreSQL desde Python

El programa funciona de la siguiente manera:

  • Lee los datos del fichero data.ini.
  • Crea una nueva conexión con PostgreSQL al llamar a la función connect.
  • Crea un nuevo cursor y ejecuta una sentencia SQL que simplemente pide el número de versión del servidor SELECT version().
  • Lee el resultado usando la función de cursor fetchone y lo imprime.
  • Por último cierra la comunicación con la base de datos llamando a la función close() del cursor y de la conexión.

Crear una tabla nueva en PostgreSQL desde Python:

En el siguiente ejemplo vamos a crear una tabla nueva en nuestra base de datos, la tabla se llamará persona y está definida de la siguiente manera:

CREATE TABLE persona( 
    persona_id SERIAL PRIMARY KEY,
    nombre VARCHAR(50) NOT NULL,
    apellido1 VARCHAR(50) NOT NULL, 
    apellido2 VARCHAR(50)
    );

En nuestro fichero main.py pondremos el siguiente código que ejecutará la sentencia SQL de creación de tabla que hemos guardado en la variable sentenciaSQL:

import psycopg2
from config import config

def crear_tabla():
    # Ejecutamos una sentencia SQL que crea una tabla nueva
    sentenciaSQL = """CREATE TABLE persona( 
    persona_id SERIAL PRIMARY KEY,
    nombre VARCHAR(50) NOT NULL,
    apellido1 VARCHAR(50) NOT NULL, 
    apellido2 VARCHAR(50)
    ); """

    conn = None
    try:
        # Leemos los parámetros de conexión
        params = config()
        conn = psycopg2.connect(**params)
        cur = conn.cursor()
        # Ejecutamos la sentencia de creación de tabla
        cur.execute(sentenciaSQL)
        conn.commit()

        # Cerramos la comunicación con PostgreSQL
        cur.close()
    except (Exception, psycopg2.DatabaseError) as error:
        print(error)
    finally:
        if conn is not None:
            conn.close()
            print('Conexión con la base de datos cerrada.')

if __name__ == '__main__':
    crear_tabla()

Si vamos a PostgreSQL podremos ver que se ha creado la tabla persona:

Conectar a PostgreSQL desde Python

Insertar datos en PostgreSQL desde Python:

En el siguiente código vamos a crear una entrada en la tabla persona con los datos siguientes:

  • nombre = Pedro
  • apellido1 = López
  • apellido2 = Esteban
import psycopg2
from config import config

def insertar_persona(nom, ape1, ape2):
    # Ejecutamos una sentencia SQL que inserta una persona nueva en la tabla persona
    sentenciaSQL = """INSERT INTO persona 
    (nombre, apellido1, apellido2)
    VALUES (%s,%s,%s); """

    conn = None
    try:
        # Leemos los parámetros de conexión
        params = config()
        conn = psycopg2.connect(**params)
        cur = conn.cursor()

        # Ejecutamos la sentencia SQL
        cur.execute(sentenciaSQL,(nom, ape1, ape2))
        conn.commit()

        # Cerramos la comunicación con PostgreSQL
        cur.close()
    except (Exception, psycopg2.DatabaseError) as error:
        print(error)
    finally:
        if conn is not None:
            conn.close()

if __name__ == '__main__':
    insertar_persona('Pedro','López','Esteban')

La tabla quedará así:

Conectar a PostgreSQL desde Python

Si ejecutamos el programa más de una vez iremos insertando entradas idénticas en la tabla persona porque la PRIMARY KEY de la tabla es persona_id y no tenemos restricciones de repetición tales como UNIQUE.

Actualizar datos en PostgreSQL desde Python:

El siguiente programa parte de que tenemos los siguientes registros en la tabla persona:

Conectar a PostgreSQL desde Python

Queremos cambiar el registro con persona_id=3 por uno con los datos:

  • nombre = Javier
  • apellido1 = Arévalo
  • apellido2 = Baeza

Usaremos el siguiente código:

import psycopg2
from config import config

def modificar_persona(nom, ape1, ape2,id):    
    sentenciaSQL = """UPDATE persona 
    SET nombre = %s, apellido1 = %s, apellido2= %s
    WHERE persona_id = %s; """

    conn = None
    try:
        # Leemos los parámetros de conexión
        params = config()
        conn = psycopg2.connect(**params)
        cur = conn.cursor()

        # Ejecutamos la sentencia SQL
        cur.execute(sentenciaSQL,(nom, ape1, ape2,id))
        conn.commit()

        # Cerramos la comunicación con PostgreSQL
        cur.close()
    except (Exception, psycopg2.DatabaseError) as error:
        print(error)
    finally:
        if conn is not None:
            conn.close()

if __name__ == '__main__':
    modificar_persona('Javier','Arévalo','Baeza',3)

Conectar a PostgreSQL desde Python

Consultar datos en PostgreSQL desde Python:

Una de las sentencias más utilizadas en cualquier base de datos es SELECT, vamos a ver cómo utilizarla desde Python.

Utilizar la función fetchone:

En el siguiente ejemplo veremos los nombres de pila de las personas de la tabla persona utilizando la función fetchone del cursor:

import psycopg2
from config import config

def mostrar_persona():    
    sentenciaSQL = """SELECT persona_id, nombre 
    FROM persona ORDER BY nombre"""

    conn = None
    try:
        # Leemos los parámetros de conexión
        params = config()
        conn = psycopg2.connect(**params)
        cur = conn.cursor()

        # Ejecutamos la sentencia SQL
        cur.execute(sentenciaSQL)
        # podemos mostrar la cantidad de resultados obtenidos
        print("Cantidad de personas: ", cur.rowcount)
        row = cur.fetchone()

        #Creamos un bucle para imprimir los nombres
        while row is not None:
            print(row)
            row = cur.fetchone()
        # Cerramos la comunicación con PostgreSQL
        cur.close()
    except (Exception, psycopg2.DatabaseError) as error:
        print(error)
    finally:
        if conn is not None:
            conn.close()

if __name__ == '__main__':
    mostrar_persona()

El resultado del programa es éste:

Conectar a PostgreSQL desde Python

Utilizar la función fetchall:

En el siguiente ejemplo veremos los nombres de pila de las personas de la tabla persona utilizando la función fetchall del cursor:

import psycopg2
from config import config

def mostrar_persona2():    
    sentenciaSQL = """SELECT persona_id, nombre, apellido1 
    FROM persona ORDER BY apellido1"""

    conn = None
    try:
        # Leemos los parámetros de conexión
        params = config()
        conn = psycopg2.connect(**params)
        cur = conn.cursor()

        # Ejecutamos la sentencia SQL
        cur.execute(sentenciaSQL)
        rows = cur.fetchall()
        # podemos mostrar la cantidad de resultados obtenidos
        print("Cantidad de personas: ", cur.rowcount)

        # Creamos un bucle para imprimir los nombres
        for row in rows:
            print(row)

        # Cerramos la comunicación con PostgreSQL
        cur.close()
    except (Exception, psycopg2.DatabaseError) as error:
        print(error)
    finally:
        if conn is not None:
            conn.close()

El resultado del programa es éste:

Conectar a PostgreSQL desde Python

Borrar registro de PostgreSQL desde Python:

Vamos a crear un programa para borrar registros de la tabla persona, se le pasará el parámetro persona_id para que borre solamente el registro que coincida:

import psycopg2
from config import config

def borrar_persona(id):
    # Ejecutamos una sentencia SQL que borra una persona de la tabla
    sentenciaSQL = """DELETE FROM persona
    WHERE persona_id = %s"""

    conn = None
    try:
        # Leemos los parámetros de conexión
        params = config()
        conn = psycopg2.connect(**params)
        cur = conn.cursor()

        # Ejecutamos la sentencia SQL
        cur.execute(sentenciaSQL,(id,))
        borrados = cur.rowcount
        conn.commit()
        # Cerramos la comunicación con PostgreSQL
        cur.close()
    except (Exception, psycopg2.DatabaseError) as error:
        print(error)
    finally:
        if conn is not None:
            conn.close()
    return borrados

if __name__ == '__main__':
    personas_borradas = borrar_persona(1)
    print('El número de personas borradas es: ', personas_borradas)

Como se puede ver en la tabla personas ha desaparecido el registro con persona_id = 1 que era el de Pedro López Esteban.

Conectar a PostgreSQL desde Python