SQLAlchemy, установите значение столбца по умолчанию в ForeignKeyConstraint - PullRequest
0 голосов
/ 27 мая 2020

Я использую значение по умолчанию для столбца, следуя совету в этом сообщении: SQLAlchemy устанавливает значение столбца по умолчанию в зависимости от ID , но, к сожалению, не работает. Вероятно, из-за того, что указанный столбец c и ссылочный столбец находятся в составных отношениях ForeignkeyConstaint с другой таблицей, поэтому я получаю ошибку «несоответствие внешнего ключа»: МЕТОД 1) Когда вставлено значение по умолчанию: (sqlite3.OperationalError) foreign несоответствие ключей - "obj" ссылается на "obj_map" [SQL: INSERT INTO obj (otype, otype_id) VALUES (?,?)] [параметры: ('thing',)]

МЕТОД 2) в обойти указанную выше ошибку. Я также пытался предоставить второй FK напрямую, но он также не работает (sqlite3.OperationalError) Несоответствие внешнего ключа - "obj" ссылается на "obj_map" [SQL: INSERT INTO obj (otype, otype_id) VALUES (? ,?)] [параметры: ('вещь', 2)]

вот код:

from sqlalchemy import (Column, Integer, String, create_engine,
                        ForeignKey, ForeignKeyConstraint)
# Table, MetaData
from sqlalchemy.orm import create_session, Session  # mapper,
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql import select  # , func
from rsk_app.sgr.sgr_config import _gen_sqlite_str as sqliteuri
from sqlalchemy.interfaces import PoolListener
# %%
Base = declarative_base()
in_memory_db = True

def default_obj_id(context):
    current_type = context.get_current_parameters()['otype']
    statement = select(
        [ObjMap.id]).where(ObjMap.__table__.c.label == current_type)
    print('SQL STATEMENT ----->\n', str(statement))
    return statement


class ObjMap(Base):
    __tablename__ = 'obj_map'
    id = Column(Integer, primary_key=True)
    label = Column(String, nullable=False, unique=True)
    parent_id = Column(Integer, ForeignKey('obj_map.id'), nullable=True)
    schema = Column(String)


class Obj(Base):
    __tablename__ = 'obj'
    id = Column(Integer, primary_key=True)
    otype = Column(String, nullable=False)
    otype_id = Column(Integer, nullable=False, default=default_obj_id)
    __mapper_args__ = {'polymorphic_on': otype}
    __table_args__ = (
        ForeignKeyConstraint(
            ['otype_id', 'otype'],
            ['obj_map.id', 'obj_map.label'],
            name='uk_obj_type'),)


class Thing(Obj):
    __tablename__ = 'thing'
    id = Column(Integer, ForeignKey(Obj.id), primary_key=True)
    info = Column(String)
    __mapper_args__ = {'polymorphic_identity': 'thing'}


class ForeignKeysListener(PoolListener):
    def connect(self, dbapi_con, con_record):
        db_cursor = dbapi_con.execute('pragma foreign_keys=ON')

if in_memory_db:
    db_full = r'sqlite://'

engine = create_engine(db_full, echo=True, listeners=[ForeignKeysListener()])
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
s = Session(engine)
s = create_session(bind=engine, autoflush=True, autocommit=False)
# %%

def save_obj(obj):
    s.add(obj)
    try:
        s.commit()
    except Exception as e:
        s.rollback()
        print('===============NOT SAVED=========\n', str(e))

base_obj = ObjMap(label='object', schema='schema1')
save_obj(base_obj)

thing_obj = ObjMap(label='thing', schema='schema3',
                   parent_id=base_obj.id)
save_obj(thing_obj)

# CASE 1 : Should get the id from default function
other_thing = Thing(info='this is OTHER thing')
save_obj(other_thing)

# CASE 2--> insert providing object id:  Fails on composite FK insertion
one_thing = Thing(info='this is ONE thing', otype_id=thing_obj.id)
save_obj(one_thing)

s.close()
...