SQLAlchemy Создать представление в PostgresQL

2

Я пытаюсь создать представление с SQLAlchemy с Postgresql в качестве базовой БД. Отдельный запрос выбора для создания представления работает хорошо и возвращает результаты, но когда я использую его в представлении создания, я получаю ошибку sqlalchemy.exc.NoSuchTableError: популярный, которая означает, что представление не выбирается. Я получаю сообщение об ошибке при попытке выбрать из представления. Создание представления не выдает никакой ошибки, но не создает представление. Вот мой код:

from sqlalchemy import *
import sqlalchemy as db
from sqlalchemy import func
from sqlalchemy import desc
from sqlalchemy import Table
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Executable, ClauseElement

try:
    engine = db.create_engine('postgresql://user:pass@localhost:5432/db_name')
    connection = engine.connect()

except:
    print('Error establishing DB connection')

# Import metadata
metadata = db.MetaData()

# Import articles, authors and log tables
art = db.Table('articles', metadata, autoload=True, autoload_with=engine)
aut = db.Table('authors', metadata, autoload=True, autoload_with=engine)
log = db.Table('log', metadata, autoload=True, autoload_with=engine)


class CreateView(Executable, ClauseElement):
    def __init__(self, name, select):
        self.name = name
        self.select = select


@compiles(CreateView)
def visit_create_view(element, compiler, **kw):
    return "CREATE VIEW %s AS %s" % (
         element.name,
         compiler.process(element.select, literal_binds=True)
         )



# Method to create view with top three articles
def view_top_three():
    top_three_view = CreateView('popular', db.select([art.columns.title, func.count(log.columns.path)]) \
        .where(func.concat('/article/', art.columns.slug) == log.columns.path) \
        .where(log.columns.path != "/") \
        .group_by(log.columns.path, art.columns.title) \
        .order_by(desc(func.count(log.columns.path))) \
        .limit(3))

    engine.execute(top_three_view)
    v = Table('popular', metadata, autoload=True, autoload_with=engine)
    for r in engine.execute(v.select()):
        print(r)


# Call the method which creates view and selects from view
view_top_three()

Любая помощь будет оценена.

  • 0
    Слабо связанные: stackoverflow.com/questions/45347565/…
  • 0
    Большое спасибо @ IljaEverilä за указание на этот пост. Проблема заключалась в автоматической фиксации. Добавление .execution_options (autocommit = True) при создании движка решило мою проблему
Показать ещё 1 комментарий
Теги:
sqlalchemy

2 ответа

0
Лучший ответ

Я нашел решение. Проблема была связана с автокоммитом. Установка true для autocommit при создании движка решает проблему следующим образом:

engine = db.create_engine('postgresql://user:pass@localhost:5432/db_name').execution_options(autocommit=True)

Специальное упоминание @ilja-everilä

1

Поскольку ваш CreateView наследует от Executable и ClauseElement, он не считается операцией изменения данных. Другими словами

engine.execute(top_three_view)

выполняет инструкцию CREATE VIEW и затем неявно выполняет откат, когда соединение возвращается в пул.

Вместо этого он должен быть подклассом DDLElement, как показано в вики рецептов использования. Простое изменение базового класса позволит автокоммиту SQLAlchemy работать должным образом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню