En este ejemplo vamos a aprender a usar una conexion de PostgreSQL en Python a traves de la biblioteca psycopg2, la cual es un modulo que nos permite ademas hacer consultas desde codigo con la sintaxis SQL.

Requerimientos

Para este ejemplo como es una introduccion a una biblioteca vamos a usar dos servicios que nos ayudaran a practicar sin tener que instalar nada. estos seran Replit y Heroku Postgres

  • Cuenta de Replit
  • Cuenta de Heroku

Creacion de un entorno virtual

crea un entorno virtual:

python -m venv venv

otra opcion tambien es:

virtualenv venv

activate el entorno virtual:

source ./venv/bin/activate

Instalación de psycopg2

pip install psycopg2

linux

Si estas en Linux (Ubuntu), es probable que necesites instalar esta dependencia del sistema, para que puedes isntalar psycopg2.

sudo apt-get install libpq-dev

Conexion a PostgreSQL

import psycopg2

host = "localhost"
database = "demodb"
username = "postgres"
password = "mysecretpassword"
port = 5432

conn = None
cur = None

try:
    conn = psycopg2.connect(
        host=host,
        database=database,
        user=username,
        password=password,
        port=port
    )

    # cur = conn.cursor()
    # cur.close()

except Exception as error:
    print(error)
finally:
    if cur is not None:
        cur.close()
    if conn is not None:
        conn.close()

Creacion de Base de datos

CREATE DATABASE demodb;

create TABLE

create_table = """
  CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL
    )
"""

cur.execute(create_table)
conn.commit()

Insertar un dato

    cur = conn.cursor()
    cur.execute(
        "INSERT INTO users (name, email, password) VALUES (%s, %s, %s)",
        ("Ryan Ray", "ryan@gmail.com", "ryan123"))
    conn.commit()

O puedes usar variables

    insert_query = "INSERT INTO users (name, email, password) VALUES (%s, %s, %s)"
    new_user = ("John Doe", "john@gmail.com", "password")

    cur.execute(insert_query, new_user)

Returning

Ahora si por alguna razon queremos que la consulta nos devuelva el dato que acaba de guardar en la table podemos usar la palabra RETURNING de postgreSQL.

Añade el returning y el fetchone para obtener el nuevo dato:

     cur = conn.cursor()
    cur.execute("INSERT INTO users (name, email, password) VALUES (%s, %s, %s) RETURNING *", ("Joe", "joe123@gmail.com", "joe1234"))
    new_user = cur.fetchone()
    print(new_user)

Insertar multiples datos

    input_multiple = [
        ("Ryan ray", "ryan@gmail.com", "somepassword"),
        ("Jane Doe", "jane@gmail.com", "password"),
        ("John Smith", "joh@gmail.com", "password")
    ]
    insert_users = "INSERT INTO users (name, email, password) VALUES (%s, %s, %s)"
    for input in input_multiple:
      cur.execute(insert_users, input)

    conn.commit()

executeMany()

insertar multiples datos a traves de un executemany:

    input_multiple = [
        ("Ryan ray", "ryan@gmail.com", "somepassword"),
        ("Jane Doe", "jane@gmail.com", "password"),
        ("John Smith", "joh@gmail.com", "password")
    ]
    insert_users = "INSERT INTO users (name, email, password) VALUES (%s, %s, %s)"
    cur.executemany(insert_users, input_multiple)

select * from users

    cur.execute("SELECT * FROM users")
    print(cur.fetchall())

    conn.commit()

Al ser una tupla la repuesta, puedes recorrerla con un bucle for:

    cur.execute("SELECT * FROM users")
    for row in cur.fetchall():
        print(row)

o tambien puedes acceder a los indicies de la tupla:

    cur.execute("SELECT * FROM users")
    for row in cur.fetchall():
        print(row[0], row[1])

Dictionary

por defecto los datos que obtenemos como respuesta a las consutlas son Tuples, pero si queremos obtener tambien los nombres de las columnas y los datos en un formato Dictionary podemos hacer esto:

import psycopg2.extras

    conn = psycopg2.connect(
        ...
    )
    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)

    for row in cur.fetchall():
        print(row["name"], row["password"])

En caso quieras obtener un verdadero diccionario con pares Clave/Valor

Actualizar Datos

    update_user = "UPDATE users SET password = CONCAT(password, %s) WHERE id = %s"
    cur.execute(update_user, ("secretpassword", 3))

    cur.execute('SELECT * FROM users')
    for row in cur.fetchall():
        print(row)
  
    conn.commit()

delete

    delete_user = "DELETE FROM users WHERE id = %s"
    delete_input = 2
    cur.execute(delete_user, (delete_input,))

    cur.execute('SELECT * FROM users')
    for row in cur.fetchall():
        print(row)

drop table

    cur.execute("DROP TABLE IF EXISTS users")

    conn.commit()

with clause

con la palabra with, no tenemos que cerrar la conexion del cursor manualmente. ademas se ha quitado la variable cur, debido a with. Tampoco es necesario manejar si cur es null ya que no es manejado por nosotros.

...
conn = None

try:
    with psycopg2.connect(
        host=host,
        database=database,
        user=username,
        password=password,
        port=port
    ) as conn:
        with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
            create_table = """
            CREATE TABLE IF NOT EXISTS users (
                id SERIAL PRIMARY KEY,
                name VARCHAR(255) NOT NULL,
                email VARCHAR(255) NOT NULL,
                password VARCHAR(255) NOT NULL
            )
            """

            cur.execute(create_table)
            ...
except Exception as error:
    print(error)
finally:
    if conn is not None:
        conn.close()

Recursos