Elixir (SqlAlchemy): relações entre 3 tabelas com chaves primárias compostas
-
08-07-2019 - |
Pergunta
Eu tenho 3 tabelas:
- tabela A Empresa com chave primária
(company_id)
- tabela de uma página com
(company_id, url)
chave primária e uma volta de chave estrangeira a Empresa - mesa Um Attr com
(company_id, attr_key)
chave primária e uma volta de chave estrangeira para empresa.
A minha pergunta é como construir a relação ManyToOne de Attr volta à página usando as colunas existentes na Attr, ou seja company_id
e url
?
from elixir import Entity, has_field, setup_all, ManyToOne, OneToMany, Field, Unicode, using_options
from sqlalchemy.orm import relation
class Company(Entity):
using_options(tablename='company')
company_id = Field(Unicode(32), primary_key=True)
has_field('display_name', Unicode(255))
pages = OneToMany('Page')
class Page(Entity):
using_options(tablename='page')
company = ManyToOne('Company', colname='company_id', primary_key=True)
url = Field(Unicode(255), primary_key=True)
class Attr(Entity):
using_options(tablename='attr')
company = ManyToOne('Company', colname='company_id', primary_key=True)
attr_key = Field(Unicode(255), primary_key=True)
url = Field(Unicode(255)) #, ForeignKey('page.url'))
# page = ManyToOne('Page', colname=["company_id", "url"])
# page = relation(Page, backref='attrs', foreign_keys=["company_id", "url"], primaryjoin=and_(url==Page.url_part, company_id==Page.company_id))
Eu já comentou algumas tentativas falhadas.
No final, Attr.company_id terá de ser um ForeignKey para ambos Página and Company (bem como uma chave primária em Attr).
Isso é possível?
Solução
Sim, você pode fazer isso. O Elixir não tem um construído em forma de fazer isso, mas porque é um wrapper fino em SQLAlchemy você pode convencê-la a fazer isso. Porque Elixir não tem um conceito de uma relação muitos-para-um que reutilizações colunas que você precisa para usar o GenericProperty com a propriedade relação SQLAlchemy e adicione a chave estrangeira utilizando as opções da tabela existente. O código a seguir deve fazer o que quiser:
from elixir import Entity, has_field, setup_all, ManyToOne, OneToMany, Field, Unicode, using_options, using_table_options, GenericProperty
from sqlalchemy.orm import relation
from sqlalchemy import ForeignKeyConstraint
class Company(Entity):
using_options(tablename='company')
company_id = Field(Unicode(32), primary_key=True)
display_name = Field(Unicode(255))
pages = OneToMany('Page')
class Page(Entity):
using_options(tablename='page')
company = ManyToOne('Company', colname='company_id', primary_key=True)
url = Field(Unicode(255), primary_key=True)
attrs = OneToMany('Attr')
class Attr(Entity):
using_options(tablename='attr')
page = ManyToOne('Page', colname=['company_id', 'url'], primary_key=True)
attr_key = Field(Unicode(255), primary_key=True)
using_table_options(ForeignKeyConstraint(['company_id'], ['company.company_id']))
company = GenericProperty(relation(Company))