LINUX.ORG.RU

6
Всего сообщений: 47

добавить MetaData к существующей таблице (SQLAlchemy)

Существуют таблицы, они заполнены и используются. И, возникла необходимость в миграции. Выбрал alembic и он требует MetaData object.

Как можно добавить к существующей таблице объект MetaData?

Таблица создавалась средствами SQLAlchemy:


class ATable(Base):
    
    __tablename__ = 'atable'

    id = Column(Integer, primary_key=True)
    type = Column(String, nullable=False)
    name = Column(String, nullable=False)
    # ...
    def __init__(self, **kwa):
        self.__dict__.update(kwa)
    
    def __repr__(self):
        return str(self.__dict__)

# ...
from sqlalchemy import create_engine
from sqlalchemy import MetaData
    
engine = create_engine(dbsetting, echo=True)
metaData = MetaData(bind=engine)
metaData.create_all(tables=[ATable.__table__])

P.S. Хотя, может эти метаданные есть, но где их искать?

ERROR [alembic.util.messaging] Can't proceed with --autogenerate option; environment script /home/user/project/alembic/env.py does not provide a MetaData object or sequence of objects to the context.
  FAILED: Can't proceed with --autogenerate option; environment script /home/user/project/alembic/env.py does not provide a
  MetaData object or sequence of objects to the context.

 ,

scisearcher ()

select, slice как взять count?

stmt = (
    select(PollsQuestion)
)
query = stmt.slice(
    p_start,
    p_end,
)
res = await session.execute(query)
print(QS.qs2dict(res.fetchall()))

А как взять count с таблицы PollsQuestion, не делая втрого запроса? Может быть подзапросом или еще как-то

 

serg002 ()

subquery count

stmt = (
    select(PollsQuestion.id)
)
res = await session.execute(stmt)

как в эту выборку добавить count? В идеале чтобы было:

{'res': [PollsQuestion], 'count': x}

Как это реализовать в алхимии?

 

serg002 ()

Пагинация

aiohttp + sqlalchemy. Не могу устроить пагинацию на выборку. Как это делается? Заюзал SQLAlchemy-Paginator - не работает. Подскажите, что заюзать или как это вообще сделать?

 , ,

serg002 ()

sqlalchemy как обновить таблицу

Имеется DB модель и DTO к ней. После выполнения выборки из БД в виде списка DTO, с элементами списка выполняется работа — поля обновляются и нужно подключиться к БД и обновить строки таблицы, соответсвующие DTO-шкам.

Как это сделать? застрял опять

@dataclass
class MyData1:
    name: str
    id: int = None
    @classmethod
    def fromMyTable1(cls, elem):
        return cls(id=elem.id, name=elem.name)

    @classmethod
    def toMyTable1(cls, elem):
        return MyTable1(id=elem.id, name=elem.name)

class MyTable1(Base):

    __tablename__ = 'MyTable1'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)


def getAll() -> List[MyData1]:
    result = []
    with sessionScope() as session:
        rows = session.query(MyTable1).all()
        for row in rows:
            result.append(MyData1.fromMyTable1(row))
    return result

def insertAll(datas: List[MyData1]):
    with sessionScope() as session:
        for data in datas:
            row = MyData1.toMyTable1(data)
            print(row.id, row.name)
            # HOW TO UPDATE  ???

P.S. Нужно разделить выборку данных и обновление, и делать это не в рамках одной сессии. Т.е. я выбрал данные, поработал и потом сохранил:

myDatas = getAll()
for data in myDatas:
    data.name = 'my_{}'.format(data.name)
insertAll(myDatas)

P.S.2 почемуто не элегантным мне кажеться такое решение

def insertAll(datas: List[MyData1]):
    with sessionScope() as session:
        for data in datas:
            row = MyData1.toMyTable1(data)
            rows = session.query(MyTable1).filter(MyTable1.id==row.id) \
                          .update({'name': row.name})
как всегда, сам не знаю, но что-то не устраивает ))) может можно не перебирать все поля?

 ,

scientistpython ()

как правильно обращаться с Алхимией

Как вернуть реальные данные из БД в Академии в виде объектов класса MySubject с заполненными полями?

в этом коде возвращается список словарей с ключем '_sa_instance_state' и значением sqlalchemy.orm.state.InstanceState:

def getMySubject(
        creation_date: datetime.date) -> List[MySubject]:

    subjects= []

    with sessionScope() as session:
        rows = (session 
               .query(MySubject) 
               .filter(MySubject.creation_date ==
                   creation_data)
               # ...
               .all()
        )
        for row in rows:
            subjects.append(row)
    return subjects

 ,

scientistpython ()

sqlalchemy проверить на дубликат перед вставкой

В sqlalchemy существует метод для проверки на дубликат перед вставкой записи?

Есть модель-таблица

class MyTable(Base):

    __tablename__ = 'MyTable'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    date = Column(Date, nullable=False)
    count = Column(Integer, nullable=False)

    __table_args__ = (UniqueConstraint('name', 'date', name='uniq_idx_1'), )

Метод вставки

def insert(myTable: MyTable) -> None:
    with sessionScope() as session:
        session.add(myTable)
будет бросать исключение, если идет дубликат по комбинации уникальных полей name и date. Как бы предварительно перед session.add прочекать строчку для вставки на отсуствие дубликата? обязательно ли все записи выбирать?

 ,

scientistpython ()

Там алхимию подвезли с асинхронностью и тайп-хинтингом

SQLAlchemy 1.4.0 Released, а новости до сих пор нет, напишите кто-нибудь обзор. Как никак самый большой выпуск за несколько лет.

 , ,

vvn_black ()

sqlalchemy session in Process

Из [1] следует, что сессия Session() д.б. едина в приложениии. А что делать, если в основной программе нужно открыть сессию и в отдельном процессе-демоне нужно открыть сесссию к одной и тойже БД.

[1] https://docs.sqlalchemy.org/en/13/orm/session_basics.html

 , ,

scientistpython ()

python sqlalchemy: можно ли отключить autocommit для expression language?

Доброго времени суток

Сабж. Насколько я понял из документации, работа с sqlalchemy возможна в 2 вариантах: Expression Language и ORM

В документации по ORM части есть информация, как отключить autocommit. В документации по Expression Language ничего подобного не нашёл :\

Пока я не уверен, что мне стоит использовать. Возможно, придётся перейти на ORM. Но хотелось бы понять, можно ли убрать autocommit в Expression Language, или единственная возможность - собирать данные в своём коде и выполнять execute с массивом

 ,

router ()

Выбрать всю строку при группировки SQLAlchemy как?

Имеется табличка:

 id | createdDate | user | kind |  team  
----+-------------+------+------+--------
  2 | 2020-12-12  | y    | A    | red
  3 | 2020-12-12  | z    | A    | blue
  4 | 2020-12-12  | y    | A    | green
  1 | 2020-09-11  | x    | A    | red
  5 | 2020-12-13  | q    | B    | orange
  6 | 2020-12-22  | t    | A    | green

При выполнении группировки в список попадают значения поля user:

session.query(A.team, func.array_agg(A.user, type_=ARRAY(String)), 
              func.count(A.user)).group_by(A.team).filter(A.kind == 'A')
('blue', ['z'], 1)
('green', ['y', 't'], 2)
('red', ['y', 'x'], 2)
А как вместо значений поля user сделать элементом списка всю строку:
('blue', [('2020-12-12', 'z', 'A', 'blue', '2020-10-10')], 1)
('green', [('2020-12-12', 'y', 'A', 'green', '2020-11-10'), ('2020-12-22', 't', 'A', 'green', '2020-11-10')], 2)
('red', [('2020-12-12', 'y', 'A', 'red', '2020-10-10'), ('2020-09-11', 'x', 'A', 'red', '2020-10-10')], 2)
?????

P.S. вроде можно заджойница, но не могу синтаксически построить конструкцию никак

session.query(A.team, func.array_agg(A.id, type_=ARRAY(Integer)), 
              func.count(A.id)).group_by(A.team).filter(A.kind == 'A') ... .join(A ...)

 , ,

scientistpython ()

SQLAlchemy кустомный слайс

имеется таблица

 user | kind |  team  
------+------+--------
 y    | A    | red
 z    | A    | blue
 y    | A    | green
 x    | A    | red
 q    | B    | orange
 t    | A    | green

и вот такая выборка

session.query(A.team, func.array_agg(A.user, type_=ARRAY(String)), 
              func.count(A.user)).group_by(A.team)\
              .filter(A.kind == 'A')
('blue', ['z'], 1)
('green', ['y', 't'], 2)
('red', ['y', 'x'], 2)
Третий столбец - число user в списке из второго столбца.

Как бы мне к ней сделать метод slice(idx1, idx2), который будет порционно выдавать списки пользователей? Например,

slice(0,3)
('blue', ['z'], 1)
('green', ['y', 't'], 2)
slice(3,4)
('red', ['y', 'x'], 2)

 , ,

scientistpython ()

шаблон Repository с SQLAlchemy

Как корректно заюзать Engine и Session из SQLAlchemy для создания репозитория моделей? Нужно ли делать синглтон(ы) для них или пусть каждая модель запускает свой движек и сессию?

Base = declarative_base()
class A(Base):
    ...

class B(Base):
    ...

class Store:

    def __init__(self):
        psql = 'postgresql://user:123@localhost/pdb'
        self.engine = create_engine(psql)
        self.sessionMaker = sessionmaker(bind=self.engine)
        self.sessionMaker = self.sessionMaker()

    def __del__(self):
        self.sessionMaker.commit()
        self.sessionMaker.close_all()    

class AStore(Store):

    def reCreate(self):
        Base.metadata.drop_all(bind=self.engine, tables=[A.__table__])   
        Base.metadata.create_all(self.engine, tables=[A.__table__])  

    def adds(self, rows):     
        for row in rows:
            params = A(**row);
            self.sessionMaker.add(params)
        self.sessionMaker.commit()   

class BStore(Store):
    ...

 , , ,

scientistpython ()

sqlalchemy собственная функция при группировки

Как при группировки подставить собственную функцию, которая сожержимое столбцов запихивает в список.

class A(Base):
    
    __tablename__ = 'A'

    id = Column(Integer, primary_key=True)
    a = Column(String)
    b = Column(String)

=> select * from public."A";
 id | a | b 
----+---+---
  1 | q | w
  2 | q | v
  3 | e | r
(3 rows)

Нужна своя функция, которая при группировки будет добавлять в список содержимое столбца

session.query(A.a,  my_concatenate_funct).group_by(A.a)

('q', ['w', 'v'])
('e', ['r'])

 ,

scientistpython ()

Есть смысл использовать SQLAlchemy для своих программ?

Временами очень надо использовать БД и использую я postgres. Пишу как обезьяна, с помощью запичканных в функции cursor.execute() У такого способа есть одно преимущество, полученный через него row можно отправить в конструктор. Есть смысл для мелких проектов (не больше 3000 строк) использовать SQLAlchemy?

Еще я активно использую psycopg2.pool

 ,

steemandlinux ()

Почему не вставляются данные в таблицу?

есть скрипт, который использует sqlAlchemy и sqlite3. он отрабатывает без проблем: https://github.com/zlodiak/sql_alchemy_sqlite/blob/master/index.py

есть другой похожий скрипт, который использует sqlAlchemy и postgresql и он не отрабатывает(таблица создаётся, но она пустая):

import random
from sqlalchemy import create_engine, Table, MetaData, select, Column, String, Integer
from sqlalchemy.sql import and_, or_, not_
import psycopg2

engine = create_engine('postgresql://alchemy_user:qwerty@localhost:5432/db_alchemy')
connection = engine.connect()
metadata = MetaData()

quotes = Table('quotes', metadata,
    Column('id', Integer, primary_key=True),
    Column('text', Integer, nullable=False),
    Column('weight', Integer, nullable=False)
)
metadata.create_all(engine)


quotes_json = []
with open("text.txt") as file_handler:
    for line in file_handler:
        quotes_json.append({
            'text': line,
            'weight': random.randint(1, 10),
        })
connection.execute(quotes.insert(), quotes_json)


s = select([quotes]).where(and_(quotes.c.weight > 3, quotes.c.weight < 8))
result = connection.execute(s)
for row in result:
    print(row['id'], row['text'][:20] + '...', row['weight'])

сообщение об ошибке следующее:

(simple_pg) md@md ~/.MINT18/code/python/alchemy/simple_pg $ python index.py
Traceback (most recent call last):
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1225, in _execute_context
    self.dialect.do_executemany(
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py", line 854, in do_executemany
    cursor.executemany(statement, parameters)
psycopg2.errors.InvalidTextRepresentation: invalid input syntax for integer: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. 
"
LINE 1: INSERT INTO quotes (text, weight) VALUES ('Sed ut perspiciat...
                                                  ^


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "index.py", line 25, in <module>
    connection.execute(quotes.insert(), quotes_json)
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 982, in execute
    return meth(self, multiparams, params)
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/sql/elements.py", line 293, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1095, in _execute_clauseelement
    ret = self._execute_context(
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1249, in _execute_context
    self._handle_dbapi_exception(
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1476, in _handle_dbapi_exception
    util.raise_from_cause(sqlalchemy_exception, exc_info)
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 398, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 152, in reraise
    raise value.with_traceback(tb)
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1225, in _execute_context
    self.dialect.do_executemany(
  File "/home/md/.local/share/virtualenvs/simple_pg-epaYC0ys/lib/python3.8/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py", line 854, in do_executemany
    cursor.executemany(statement, parameters)
sqlalchemy.exc.DataError: (psycopg2.errors.InvalidTextRepresentation) invalid input syntax for integer: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. 
"
LINE 1: INSERT INTO quotes (text, weight) VALUES ('Sed ut perspiciat...
                                                  ^

[SQL: INSERT INTO quotes (text, weight) VALUES (%(text)s, %(weight)s)]
[parameters: ({'text': 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. \n', 'weight': 8}, {'text': 'Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. \n', 'weight': 3}, {'text': 'Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. \n', 'weight': 10}, {'text': 'Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?\n', 'weight': 5}, {'text': 'Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?\n', 'weight': 5}, {'text': 'At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. \n', 'weight': 6}, {'text': 'Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. \n', 'weight': 7}, {'text': 'Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. \n', 'weight': 9}, {'text': 'Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.', 'weight': 4})]
(Background on this error at: http://sqlalche.me/e/9h9h)

я думал, что sqlAlchemy именно для того и существует чтобы скрывать особенности различных БД и работать с ними через единый интерфейс, а оказалось, что это не так. объясните пожалуйста почему я дурак?

 , , ,

prozaik ()

возможно ли использовать sqlalchemy для read only доступа к чужой БД?

Доброго времени суток

Сабж. Документация по sqlalchemy рассказывает, как создать собственную БД и работать с ней как хранилищем объектов

А возможно ли подключиться к уже существующей БД и читать из неё объекты, не внося никаких изменений? Продублировать существующую структуру таблиц в коде - никаких проблем, главное ничего не писать в базу

 ,

router ()

SQLAlchemy. Добавить запись, ссылающуюся на две родительские

Пытаюсь вставить запись, ссылающуюся на две родительские:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import relationship

from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy import ForeignKey

Base = declarative_base()
engine = create_engine('sqlite://')
Session = sessionmaker(engine)


class Parent(Base):
    __tablename__ = 'Parent'

    link = Column('link', Integer, primary_key=True, autoincrement=True)
    name = Column('c_name', String)

    child = relationship('Child')


class Parent2(Base):

    __tablename__ = 'Parent2'

    link = Column('link', Integer, primary_key=True, autoincrement=True)
    name = Column('c_name', String)

    child = relationship('Child')


class Child(Base):
    __tablename__ = 'Child'

    link = Column('link', Integer, primary_key=True, autoincrement=True)
    parent = Column('f_parent', Integer, ForeignKey('Parent.link'), nullable=False)
    parent2 = Column('f_parent2', Integer, ForeignKey('Parent2.link'), nullable=False)
    name = Column('c_name', String)


Base.metadata.create_all(engine)
session = Session()


parent = Parent(name='qwe')
parent2 = Parent2(name='qwerty')

session.add(parent)
session.add(parent2)
session.commit()

child = Child(name='child')

parent.child.append(child)
parent2.child.append(child)

session.add_all([parent, parent2])

session.commit()

Получаю ошибку:

(sqlite3.IntegrityError) NOT NULL constraint failed: Child.f_parent2 [SQL: INSERT INTO «Child» (f_parent, f_parent2, c_name) VALUES (?, ?, ?)] [parameters: (1, None, 'child')]

Как правильно вставить такую запись?

 , ,

alexg ()

Python Peewee One-to-one

Собственно, кто работал с этой библиотекой, м.б подскажет, как тут сделать one-to-one связь? Т.е есть таблица и есть таблица на ее расширенные свойства. В каждой из таблиц должны быть ключи друг на друга. В SQAlchemy можно было просто использовать uselist=False. А тут есть только backref, как я понял. И создает он именно список.

Почему не взял SQAlchemy - peewee-async. Для SQLAlchemy ничего похожего не находил. Был, конечно, Gino для SQLA. Но я один раз взял его, намучался, и больше как-то не хочется.

P.S Прошу не разводить срач на тему Peewee vs SQAlchemy, а просто ответить, если кто использовал и знает.

 , , , ,

crarkie ()

Проблема с Flask-Admin

Всем добрый день. Разбираюсь сейчас с SQLAlchemy и Flask-Admin. Возникла такая проблема, что я не могу сохранить в админке те записи, в которых есть отношения между записями. Если запись пустая, то выскакивает следующая ошибка:

TypeError: Incompatible collection type: None is not list-like

Если же выбрать запись, которая существует, то появляется следующее:

TypeError: Incompatible collection type: Session is not list-like

Разбираюсь уже часа 3 и не могу понять в чем дело. Пробовал менять модель. Отношение 1-к-1. Определено так:

session_id = Column(ForeignKey('session.session_id'), nullable=True, default=None)
session = relationship('Session', uselist=True)

 , ,

crarkie ()