引用SQLAlchemy中的表和列名称

时间:2019-04-25 12:07:11

标签: python sqlalchemy

我有一个使用此代码(full function code over here)将触发器添加到指定表的功能:

event.listen(primary_table, 'after_create', DDL('''
    CREATE FUNCTION {primary_table_name}_validate() RETURNS TRIGGER AS $$
    DECLARE
        target RECORD;
    BEGIN
        IF (NEW.{rhs} IS NOT NULL) THEN
            SELECT {parentcol} INTO target FROM {child_table_name} WHERE {child_id_column} = NEW.{rhs};
            IF (target.{parentcol} != NEW.{lhs}) THEN
                RAISE foreign_key_violation USING MESSAGE = 'The target is not affiliated with this parent';
            END IF;
        END IF;
        RETURN NEW;
    END;
    $$ LANGUAGE plpgsql;
    CREATE TRIGGER {primary_table_name}_trigger BEFORE INSERT OR UPDATE
    ON {primary_table_name}
    FOR EACH ROW EXECUTE PROCEDURE {primary_table_name}_validate();
    '''.format(
    primary_table_name=primary_table_name,
    parentcol=parentcol,
    child_table_name=child_table_name,
    child_id_column=child_id_columns[0],
    lhs=parent_table_name + '_' + parent_id_columns[0],
    rhs=child_table_name + '_' + child_id_columns[0],
)).execute_if(dialect='postgresql'))

event.listen(primary_table, 'before_drop', DDL('''
    DROP TRIGGER {primary_table_name}_trigger ON {primary_table_name};
    DROP FUNCTION {primary_table_name}_validate();
    '''.format(primary_table_name=primary_table_name)).execute_if(dialect='postgresql'))

我不想在SQL中嵌入原始字符串,因为它会阻塞user之类的名称(对于PostgreSQL)。我不能使用SQLAlchemy的bindparam,因为它们是表名和列名,而不是数据。 SQLAlchemy offers a quoted_name and a quote_identifier似乎可以满足我的需求,但是我如何在这里使用它们?

1 个答案:

答案 0 :(得分:0)

要回答我自己的问题,DDL接受一个应用于SQL语句的context字典。这是修改后的代码:

event.listen(primary_table, 'after_create',
    DDL('''
        CREATE FUNCTION %(function)s() RETURNS TRIGGER AS $$
        DECLARE
            target RECORD;
        BEGIN
            IF (NEW.%(rhs)s IS NOT NULL) THEN
                SELECT %(parentcol)s INTO target FROM %(child_table_name)s WHERE %(child_id_column)s = NEW.%(rhs)s;
                IF (target.%(parentcol)s != NEW.%(lhs)s) THEN
                    RAISE foreign_key_violation USING MESSAGE = 'The target is not affiliated with this parent';
                END IF;
            END IF;
            RETURN NEW;
        END;
        $$ LANGUAGE plpgsql;
        CREATE TRIGGER %(trigger)s BEFORE INSERT OR UPDATE
        ON %(table)s
        FOR EACH ROW EXECUTE PROCEDURE %(function)s();
        ''',
        context={
            'table': primary_table_name,
            'function': '%s_validate' % primary_table_name,
            'trigger': '%s_trigger' % primary_table_name,
            'parentcol': parentcol,
            'child_table_name': child_table_name,
            'child_id_column': child_id_columns[0],
            'lhs': '%s_%s' % (parent_table_name, parent_id_columns[0]),
            'rhs': '%s_%s' % (child_table_name, child_id_columns[0]),
        }
    ).execute_if(dialect='postgresql')
)

event.listen(primary_table, 'before_drop',
    DDL('''
        DROP TRIGGER %(trigger)s ON %(table)s;
        DROP FUNCTION %(function)s();
        ''',
        context={
            'table': primary_table_name,
            'trigger': '%s_trigger' % primary_table_name,
            'function': '%s_validate' % primary_table_name,
        }
    ).execute_if(dialect='postgresql')
)