использование списка на JSON-типе postgresql с sqlalchemy

8

Я использую пирамиду с sqlalchemy, pyramid_tm и postgresql, чтобы проверить это.

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()


class MyList(Base):
    id = Column(Integer, primary_key=True)
    lst = Column(JSON)

Я использую postgresql 9.3+ и использую тип JSON. Когда я делаю это

mylst = MyList(lst=[])

Я могу видеть, что в базе данных также создается пустой [] список, а

def view(request):
    mylst = DBSession.query(MyList).get(1)
    mylst.lst.append('45')
    print(DBSession.is_active, DBSession.is_modified(mylst))

я могу видеть ['45'] в базе данных, а print возвращает

True, True

продолжение сверху [edit] при следующем запросе (выше уже сделано)

def view(request):
    mylst = DBSession.query(MyList).get(1)
    mylst.lst.append('65')
    print(DBSession.is_active, DBSession.is_modified(mylst))

db не будет обновляться, он все еще ['45'] и печать возвращает

True, False

Я делаю что-то неправильно или это ошибка?

Теги:
sqlalchemy
pyramid

3 ответа

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

По умолчанию SQLAlchemy отслеживает только изменения самого значения, которое работает "как положено" для простых значений, таких как целые и строки:

alice.name = "Alice"
alice.age = 8

Это также работает, когда вы присваиваете новое значение столбцу "сложного типа", например dict или list:

alice.toys = ['doll', 'teddy bear']

Однако SQLAlchemy не замечает изменений, если вы изменяете один из элементов в списке или добавляете/удаляете значение:

alice.toys[0] = 'teapot'
alice.toys.append('lego bricks')

Чтобы это работало, вы можете убедиться, что каждый раз вы назначаете новый список:

toys = alice.toys[:]  # makes a "clone" of the existing list
toys[0] = 'teapot'
toys.append('lego bricks')
alice.toys = toys

Или прочитайте главу " Отслеживание мутаций" в документации по SQLAlchemy, чтобы увидеть, как вы можете создать подкласс для списка или указания, чтобы они могли отслеживать изменения своих элементов.

Кроме того, поскольку вы упомянули, что используете Postgres - в Postgres есть специальный тип ARRAY который вы можете использовать вместо JSON если все, что вам нужно, это хранить списки. Однако сказанное выше о слежении за мутациями применимо и к столбцам типа ARRAY.

  • 0
    спасибо, это была проблема. решено :)
  • 0
    @Sergey Сергей, не могли бы вы пояснить, как изменить Column(JSON) на Column(ARRAY) ? Кажется, я должен также указать тип. Но как мне определить массив, который может содержать словари?
2

Вы можете указать экземпляр с измененным вручную

from sqlalchemy.orm.attributes import flag_modified

def view(session):
    mylst = Session.query(MyList).get(1)
    mylst.lst.append('45')
    flag_modified(mylst, 'lst') # flag its `lst' attribute is modified
    print(Session.is_active, Session.is_modified(mylst))
    # (True, True)
-2

Попробуйте DBSession.flush() после mylst.lst.append('45'). Это позволяет вам обновить БД до того, как pyramid_tm выполнит фиксацию.

Дополнительную информацию можно найти здесь: http://docs.sqlalchemy.org/en/latest/orm/session.html#flushing

  • 0
    вторая часть после коммита, извините не было так понятнее
  • 0
    Ах, хорошо, так что это следующий запрос. Я полагаю, что в консоли должна быть ошибка. Насколько многословна настройка предупреждений SQLAlchemy в development.ini? Вы также можете очистить заранее, чтобы увидеть, есть ли какие-либо ошибки.

Ещё вопросы

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