SQLAlchemy ORM - Establecimiento de relaciones
Esta sesión describe la creación de otra tabla que está relacionada con una ya existente en nuestra base de datos. La tabla de clientes contiene datos maestros de los clientes. Ahora necesitamos crear una tabla de facturas que puede tener cualquier número de facturas pertenecientes a un cliente. Este es un caso de relaciones de una a muchas.
Utilizando declarativo, definimos esta tabla junto con su clase asignada, Facturas como se indica a continuación:
from sqlalchemy import create_engine, ForeignKey, Column, Integer, String
engine = create_engine('sqlite:///sales.db', echo = True)
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
from sqlalchemy.orm import relationship
class Customer(Base):
__tablename__ = 'customers'
id = Column(Integer, primary_key = True)
name = Column(String)
address = Column(String)
email = Column(String)
class Invoice(Base):
__tablename__ = 'invoices'
id = Column(Integer, primary_key = True)
custid = Column(Integer, ForeignKey('customers.id'))
invno = Column(Integer)
amount = Column(Integer)
customer = relationship("Customer", back_populates = "invoices")
Customer.invoices = relationship("Invoice", order_by = Invoice.id, back_populates = "customer")
Base.metadata.create_all(engine)
Esto enviará una consulta CREATE TABLE al motor SQLite como se muestra a continuación:
CREATE TABLE invoices (
id INTEGER NOT NULL,
custid INTEGER,
invno INTEGER,
amount INTEGER,
PRIMARY KEY (id),
FOREIGN KEY(custid) REFERENCES customers (id)
)
Podemos comprobar que se crea una nueva tabla en sales.db con la ayuda de la herramienta SQLiteStudio.
La clase Facturas aplica la construcción ForeignKey en el atributo custid. Esta directiva indica que los valores en esta columna deben restringirse para ser valores presentes en la columna id en la tabla de clientes. Esta es una característica central de las bases de datos relacionales y es el "pegamento" que transforma la colección de tablas no conectadas para que tengan relaciones superpuestas ricas.
Una segunda directiva, conocida como relación (), le dice al ORM que la clase Invoice debe estar vinculada a la clase Customer mediante el atributo Invoice.customer. La relación () utiliza las relaciones de clave externa entre las dos tablas para determinar la naturaleza de este vínculo, determinando que es de muchos a uno.
Se coloca una directiva de relación adicional () en la clase asignada por el cliente bajo el atributo Customer.invoices. El parámetro Relationship.back_poplates se asigna para hacer referencia a los nombres de atributos complementarios, de modo que cada relación () pueda tomar una decisión inteligente sobre la misma relación expresada al revés. Por un lado, Invoices.customer se refiere a la instancia de Invoices y, por otro lado, Customer.invoices se refiere a una lista de instancias de Clientes.
La función de relación es parte de la API de relación del paquete ORM de SQLAlchemy. Proporciona una relación entre dos clases mapeadas. Esto corresponde a una relación de tabla asociativa o padre-hijo.
Los siguientes son los patrones de relación básicos encontrados:
Uno a muchos
Una relación de uno a muchos se refiere al padre con la ayuda de una clave externa en la tabla secundaria. Entonces, la relación () se especifica en el padre, como referencia a una colección de elementos representados por el hijo. El parámetro Relationship.back_poplates se utiliza para establecer una relación bidireccional en uno a varios, donde el lado "inverso" es de varios a uno.
Muchos a uno
Por otro lado, la relación Many to One coloca una clave externa en la tabla principal para hacer referencia al secundario. La relación () se declara en el padre, donde se creará un nuevo atributo de retención de escalares. Aquí de nuevo, el parámetro Relationship.back_poplates se utiliza para Bidirectionalbehaviour.
Doce y cincuenta y nueve de la noche
La relación uno a uno es esencialmente una relación bidireccional por naturaleza. El indicador de lista de usuario indica la ubicación de un atributo escalar en lugar de una colección en el lado "muchos" de la relación. Para convertir uno a varios en un tipo de relación uno a uno, establezca el parámetro uselist en false.
Muchos a muchos
La relación Many to Many se establece agregando una tabla de asociación relacionada con dos clases definiendo atributos con sus claves externas. Está indicado por el argumento secundario de la relación (). Por lo general, la tabla usa el objeto MetaData asociado con la clase base declarativa, de modo que las directivas ForeignKey pueden ubicar las tablas remotas con las que enlazar. El parámetro Relationship.back_poplates para cada relación () establece una relación bidireccional. Ambos lados de la relación contienen una colección.