使用SQLAlchemy处理Postgres继承
我有一个关于如何使用SQLAlchemy创建PostgreSQL表继承的问题。
我有这两个表:
CREATE TABLE his
(
idg integer,
idfk integer,
idh integer NOT NULL defautl nextval('his_seq'),
"type" character varying,
CONSTRAINT __his_pkey PRIMARY KEY (idh)
);
CREATE TABLE data
(
"text" character varying,
)
INHERITS (his);
在执行任何DDL命令之前,我写了这段Python代码:
from sqlalchemy import *
from sqlalchemy.orm import Session
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import event
Base = declarative_base()
class His(Base):
__tablename__ = 'his'
idg = Column(Integer())
idfk = Column(Integer())
idh = Column(Integer(), Sequence('his_seq', start=1, increment=1), primary_key=True)
type= Column(String())
__mapper_args__ = {'polymorphic_on': type}
__table_args__ = {'implicit_returning':False}
def __init__(self, idg, idfk, type):
self.idg = idg
self.idfk = idfk
self.type = type
class Data(His):
__tablename__ = None
# __mapper_args__ = {'polymorphic_identity': 'data', 'concrete':True}
__mapper_args__ = {'polymorphic_identity': 'data'}
text = Column(String())
def __init__(self, text):
self.text = text
@event.listens_for(His.__table__, 'after_create')
def create_child_tables(target, connection, **kw):
connection.execute("""
CREATE TABLE data(
) INHERITS (his)
""")
connection.execute("""
CREATE OR REPLACE FUNCTION his_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF (NEW.type='data') THEN
INSERT INTO data VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'Table type is unknown for historical porpurses.';
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
""")
connection.execute("""
CREATE TRIGGER his_insert
BEFORE INSERT ON his
FOR EACH ROW EXECUTE PROCEDURE his_insert_trigger();
""")
@event.listens_for(His.__table__, "before_drop")
def create_child_tables(target, connection, **kw):
connection.execute("drop table data")
connection.execute("drop table his")
connection.execute("drop sequence his_seq")
e = create_engine('postgresql://localhost:5433/des', echo=True)
#Base.metadata.drop_all(e)
Base.metadata.create_all(e)
s = Session(e)
s.add_all([
Data('hola'),
Data('pedorrete'),
Data('pedorrete2')
])
s.commit()
s.close()
这个例子(就像在http://www.sqlalchemy.org/trac/wiki/UsageRecipes/PostgreSQLInheritance中解释的那样)创建了两个表,但SQLAlchemy总是使用它自己的表来插入数据记录,这些记录被插入到“data”表和“his”表中,而“data”表中的“text”字段实际上是创建在“his”表里的。
那么,有没有办法告诉SQLAlchemy,“data”表必须从“his”表继承,并且必须在其中添加“text”字段,并且在我向“data”表插入任何记录时,必须使用“data”而不是“his”呢?
谢谢。
2 个回答
1
Sqlalchemy的表继承功能是希望你的子表只包含额外的数据,它会自己处理表之间的连接,以获取合并后的信息。如果你打算使用PostgreSQL自带的表继承功能,其实就不需要使用sqlalchemy的继承特性,你只需把它们当作不相关的表来处理,因为Postgres会为你完成这些工作。
为了避免重复代码,你可以把列的定义放到一个独立的类中这个类不需要继承Base
类,然后让所有的表类去继承这个独立的类。
class HisCols:
idg = Column(Integer())
idfk = Column(Integer())
idh = Column(Integer(), Sequence('his_seq', start=1, increment=1), primary_key=True)
type = Column(String())
class His(Base, HisCols):
__tablename__ = 'his'
__table_args__ = {'implicit_returning':False}
class Data(Base, HisCols):
__tablename__ = 'data'
text = Column(String())
# And if you really need it (you probably don't) you can add a relationship to the parent table
idh = Column(Integer(), ForeignKey('his.idh'), Sequence('his_seq', start=1, increment=1), primary_key=True)
parent = relationship(His)
2
SQLAlchemy尽量做到跨平台,所以它不支持很多Postgres特有的功能。这里有一个来自SQLAlchemy开发者的回答,针对一个遇到类似问题的人:
http://www.mail-archive.com/sqlalchemy@googlegroups.com/msg17443.html