Last active
October 10, 2018 01:54
-
-
Save pmart123/9d993624b32c3ae68055d12b05dc88be to your computer and use it in GitHub Desktop.
Sqlalchemy DDL with views error
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from sqlalchemy import (DDL, event, Column, TEXT, select, func, | |
FLOAT, CHAR, DATE, Table, table, MetaData) | |
from sqlalchemy.ext.declarative import declarative_base | |
from sqlalchemy.schema import CreateColumn | |
from sqlalchemy.sql.ddl import _CreateDropBase | |
from sqlalchemy.ext.compiler import compiles | |
class _View(Table): | |
__visit_name__ = 'view' | |
is_view = True | |
def View(name, metadata, selectable, replace=True, cascade=False): | |
v = _View(name, metadata) | |
t = table(name) | |
t.schema = metadata.schema | |
for c in selectable.c: | |
c._make_proxy(t) | |
event.listen( | |
metadata, 'after_create', CreateView(v, selectable, replace=replace) | |
) | |
event.listen( | |
metadata, 'before_drop', DropView(v, if_exists=True, cascade=cascade) | |
) | |
return t | |
class CreateView(_CreateDropBase): | |
__visit_name__ = 'create_view' | |
def __init__(self, element: View, selectable, on=None, bind=None, | |
replace=True): | |
super(CreateView, self).__init__(element, on=on, bind=bind) | |
self.columns = [CreateColumn(column) for column in element.columns] | |
self.selectable = selectable | |
self.replace = replace | |
@compiles(CreateView) | |
def visit_create_view(create, compiler, **kw): | |
view = create.element | |
preparer = compiler.dialect.identifier_preparer | |
text = '\nCREATE ' | |
if create.replace: | |
text += 'OR REPLACE ' | |
text += 'VIEW %s ' % preparer.format_table(view) | |
if create.columns: | |
column_names = [preparer.format_column(col.element) | |
for col in create.columns] | |
text += '(%s)' % ', '.join(column_names) | |
text += 'AS %s\n\n' % compiler.sql_compiler.process(create.selectable) | |
return text | |
class DropView(_CreateDropBase): | |
__visit_name__ = 'drop_view' | |
def __init__(self, element: View, on=None, bind=None, | |
cascade=False, if_exists=False): | |
super(DropView, self).__init__(element, on=on, bind=bind) | |
self.cascade = cascade | |
self.if_exists = if_exists | |
@compiles(DropView) | |
def compile(drop, compiler, **kw): | |
text = "\nDROP VIEW " | |
if drop.if_exists: | |
text += "IF EXISTS " | |
text += compiler.preparer.format_table(drop.element) | |
if drop.cascade: | |
text += " CASCADE" | |
return text | |
def mount_declare_schema(target_schema): | |
statement = 'CREATE SCHEMA IF NOT EXISTS {}'.format(target_schema.schema) | |
ddl_statement = DDL(statement) | |
event.listen(target_schema, 'before_create', | |
ddl_statement.execute_if(dialect='postgresql')) | |
return target_schema | |
SCHEMA_NAME = 'my_schema' | |
meta_schema = MetaData(schema=SCHEMA_NAME) | |
# Base class for models using declarative syntax | |
Base = declarative_base(metadata=meta_schema) | |
class Accounts(Base): | |
__tablename__ = 'accounts' | |
portfolio_code = Column(TEXT, primary_key=True) | |
account_code = Column(TEXT, nullable=True) | |
open_date = Column(DATE, nullable=True) | |
class Appraisals(Base): | |
__tablename__ = 'appraisals' | |
report_date = Column(DATE, primary_key=True) | |
portfolio_code = Column(TEXT, primary_key=True) | |
symbol = Column(TEXT, primary_key=True) | |
asset_class_code = Column(CHAR(1), nullable=False) | |
base_market_value = Column(FLOAT, nullable=False) | |
def broken_view_query(): | |
aa = Appraisals.__table__.alias('aa') | |
acc = Accounts.__table__.alias('acc') | |
query = select([ | |
aa.c.portfolio_code, | |
func.sum(aa.c.base_market_value).label('total_cash'), | |
]).select_from( | |
aa.join(acc, aa.c.portfolio_code == acc.c.portfolio_code) | |
).where( | |
aa.c.asset_class_code == 'c' | |
).group_by( | |
aa.c.report_date, aa.c.portfolio_code | |
) | |
return query | |
broken_view = View('broken_view', Base.metadata, broken_view_query()) | |
Base.metadata = mount_declare_schema(Base.metadata) | |
def declare(engine): | |
Base.metadata.create_all(engine) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment