Elixir (SqlAlchemy): relaciones entre 3 tablas con claves primarias compuestas
-
08-07-2019 - |
Pregunta
Tengo 3 tablas:
- Una tabla de empresa con
(company_id)
clave primaria - Una tabla de página con
(company_id, url)
clave principal & amp; una clave foránea para volver a la empresa - Una tabla Attr con
(company_id, attr_key)
clave primaria & amp; una clave foránea para la empresa.
Mi pregunta es cómo construir la relación ManyToOne desde Attr de regreso a la página utilizando las columnas existentes en Attr, es decir, company_id
y 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))
He comentado algunos intentos fallidos.
Al final, Attr.company_id deberá ser una clave foránea para Page y Company (así como una clave principal en Attr).
¿Es esto posible?
Solución
Sí, puedes hacer esto. Elixir no tiene una forma integrada de hacer esto, pero debido a que es una envoltura delgada en SQLAlchemy, puede convencerlo de que haga esto. Debido a que Elixir no tiene el concepto de una relación de muchos a uno que reutiliza las columnas existentes, debe usar GenericProperty con la propiedad de relación SQLAlchemy y agregar la clave externa usando las opciones de la tabla. El siguiente código debe hacer lo que quieras:
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))