SQLAlchemy ORM - Construindo Relacionamento
Esta sessão descreve a criação de outra tabela que está relacionada a uma já existente em nosso banco de dados. A tabela de clientes contém dados mestre de clientes. Agora precisamos criar uma tabela de faturas que pode ter qualquer número de faturas pertencentes a um cliente. Este é o caso de um para muitos relacionamentos.
Usando declarativo, definimos esta tabela junto com sua classe mapeada, Faturas conforme fornecido abaixo -
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)
Isso enviará uma consulta CREATE TABLE para o mecanismo SQLite conforme abaixo -
CREATE TABLE invoices (
id INTEGER NOT NULL,
custid INTEGER,
invno INTEGER,
amount INTEGER,
PRIMARY KEY (id),
FOREIGN KEY(custid) REFERENCES customers (id)
)
Podemos verificar se uma nova tabela foi criada em sales.db com a ajuda da ferramenta SQLiteStudio.
A classe Faturas aplica a construção ForeignKey no atributo custid. Esta diretiva indica que os valores nesta coluna devem ser restritos a valores presentes na coluna id na tabela de clientes. Esse é um recurso central dos bancos de dados relacionais e é a “cola” que transforma a coleção não conectada de tabelas em relacionamentos ricos e sobrepostos.
Uma segunda diretiva, conhecida como relacionamento (), informa ao ORM que a classe Invoice deve ser vinculada à classe Customer usando o atributo Invoice.customer. O relacionamento () usa os relacionamentos de chave estrangeira entre as duas tabelas para determinar a natureza dessa ligação, determinando que é muitos para um.
Uma diretiva relacionamento adicional () é colocada na classe mapeada do Cliente sob o atributo Customer.invoices. O parâmetro relationship.back_populates é atribuído para se referir aos nomes de atributos complementares, de modo que cada relacionamento () possa tomar uma decisão inteligente sobre o mesmo relacionamento conforme expresso no reverso. Por um lado, Invoices.customer se refere à instância Invoices e, por outro lado, Customer.invoices se refere a uma lista de instâncias Clientes.
A função de relacionamento faz parte da API de relacionamento do pacote SQLAlchemy ORM. Ele fornece um relacionamento entre duas classes mapeadas. Isso corresponde a um relacionamento pai-filho ou tabela associativa.
A seguir estão os padrões básicos de relacionamento encontrados -
Um para muitos
Um relacionamento Um para Muitos refere-se ao pai com a ajuda de uma chave estrangeira na tabela filho. relacionamento () é então especificado no pai, referenciando uma coleção de itens representados pelo filho. O parâmetro relationship.back_populates é usado para estabelecer um relacionamento bidirecional em um-para-muitos, onde o lado “reverso” é muitos para um.
Muitos para um
Por outro lado, o relacionamento Muitos para Um coloca uma chave estrangeira na tabela pai para se referir ao filho. relacionamento () é declarado no pai, onde um novo atributo de retenção escalar será criado. Aqui, novamente, o parâmetro relationship.back_populates é usado para Bidirectionalbehaviour.
Um a um
O relacionamento Um para Um é essencialmente um relacionamento bidirecional por natureza. O sinalizador uselist indica a colocação de um atributo escalar em vez de uma coleção no lado “muitos” do relacionamento. Para converter um para muitos em um tipo de relação um para um, defina o parâmetro uselist como false.
Muitos para muitos
O relacionamento muitos para muitos é estabelecido adicionando-se uma tabela de associação relacionada a duas classes, definindo atributos com suas chaves estrangeiras. É indicado pelo argumento secundário para relacionamento (). Normalmente, a Tabela usa o objeto MetaData associado à classe base declarativa, para que as diretivas ForeignKey possam localizar as tabelas remotas com as quais se vincular. O parâmetro relationship.back_populates para cada relacionamento () estabelece um relacionamento bidirecional. Ambos os lados do relacionamento contêm uma coleção.