简体   繁体   English

使用更改的python dict更新SQLAlchemy Orm对象

[英]Update SQLAlchemy orm object with changed python dict

Having issues with implementing a mutable dict that will react to changes in content. 在实施可变字典时会遇到问题,该字典将对内容的更改做出反应。 I have managed to setup SQLAlchemy to manage add and delete. 我已经成功设置SQLAlchemy来管理添加和删除。 However, changes to content of a stored dict doesn't "trigger" update of the SQLAlchemy db. 但是,对存储的dict的内容所做的更改不会“触发” SQLAlchemy数据库的更新。

I found some other questions here on stackoverflow that suggested: 我在stackoverflow上发现了其他一些建议:

By default SQLAlchemy doesn't track changes inside dict attributes. 默认情况下,SQLAlchemy不跟踪dict属性内部的更改。 To make it track changes, you can use the mutable extension: 要使其跟踪更改,可以使用可变扩展名:

I followed the example here How to implement mutable PickleTypes that automatically update on change 我在这里按照示例操作, 如何实现可变的PickleTypes,它们在更改时会自动更新

However, I can't get it to work. 但是,我无法使其正常工作。 In my example, when I change from Column(PickleType) to Column(MutableDict.as_mutable(PickleType)) the SQLAlchemy session no longer finds the object. 在我的示例中,当我从Column(PickleType)更改为Column(MutableDict.as_mutable(PickleType))时,SQLAlchemy会话不再找到该对象。 The code below illustrates what I'm trying to do. 下面的代码说明了我正在尝试做的事情。

The first code is where I set up the db and the second block I'm trying to add transactions to a person. 第一个代码是我设置数据库的地方,第二个代码是我试图向某人添加事务的地方。 I manage to add transactions and delete them but not change them. 我设法添加和删除交易,但不更改它们。 Hence, why I tried with the MutableDict class, but I don't seem to fully understand it. 因此,为什么我尝试使用MutableDict类,但是我似乎并不完全理解它。

Setup SQL db: (sqlalchemy_declarative.py) 设置SQL数据库:(sqlalchemy_declarative.py)

from sqlalchemy import Column, ForeignKey, Integer, String, PickleType
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.mutable import Mutable
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine

Base = declarative_base()


class MutableDict(Mutable, dict):

    @classmethod
    def coerce(cls, key, value):
        if not isinstance(value, MutableDict):
            if isinstance(value, dict):
                return MutableDict(value)
            return Mutable.coerce(key, value)
        else:
            return value

    def __delitem(self, key):
        dict.__delitem__(self, key)
        self.changed()

    def __setitem__(self, key, value):
        dict.__setitem__(self, key, value)
        self.changed()

    def __getstate__(self):
        return dict(self)

    def __setstate__(self, state):
        self.update(self)


class Person(Base):
    __tablename__ = 'person_object'
    # Here we define columns for the table person
    # Notice that each column is also a normal Python instance attribute.
    id = Column(Integer, primary_key=True)
    first_name = Column(String, nullable=False)
    last_name = Column(String, nullable=False)

    def __str__(self):  # prints when treated as string (for use interface)
        return f"Primary id: {self.id} \n" \
               f"First name: {self.first_name}"


class Transactions(Base):
    __tablename__ = 'transactions'
    # Here we define columns for the table address.
    # Notice that each column is also a normal Python instance attribute.
    id = Column(Integer, primary_key=True)
    transactions = Column(MutableDict.as_mutable(PickleType))
    # transactions = Column(PickleType)
    person_object_id = Column(Integer, ForeignKey('person_object.id'))
    person_object = relationship(Person)

    def update(self, tmp_dict):
        for key, value in tmp_dict.items():
            print(key, value)
            setattr(self, self.transactions[f'{key}'], value)


def create_db():
    # Create an engine that stores data in the local directory's
    # sqlalchemy_example.db file.
    engine = create_engine('sqlite:///person.db')

    # Create all tables in the engine. This is equivalent to "Create Table"
    # statements in raw SQL.
    Base.metadata.create_all(engine)

Example code: 示例代码:

from sqlalchemy_declarative import Person, Base, Transactions
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

import sqlalchemy_declarative as sqlalchemy_declarative


def main():
    sqlalchemy_declarative.create_db()
    engine = create_engine('sqlite:///person.db')
    Base.metadata.bind = engine
    db_session = sessionmaker()
    db_session.bind = engine
    session = db_session()

    transaction1 = {'item1': 'banana',
                    'item2': 'apple',
                    'item3': 'sugar',
                    'item4': 'coke',
                    'item5': 'candy'}
    transaction2 = {'item1': 'pizza',
                    'item2': 'water'}

    new_obj = Person(first_name='Bob', last_name='Smith')
    session.add(new_obj)

    new_transaction = Transactions(transactions=transaction1, person_object=new_obj)
    session.add(new_transaction)

    new_transaction = Transactions(transactions=transaction2, person_object=new_obj)
    session.add(new_transaction)
    session.commit()

    test = session.query(Transactions).all()

    for tmp in test:
        print(type(tmp.transactions))
        print(tmp.transactions == transaction1)

    test2 = session.query(Transactions).filter(Transactions.transactions == transaction1).all()
    print(test2)

    transaction1 = {'item1': 'banana',
                    'item2': 'apple',
                    'item3': 'sugar',
                    'item4': 'coke',
                    'item5': 'pineapple'}
    test2.update(transaction1)
    session.commit()

    all_transactions = session.query(Transactions).all()

    for tmp in all_transactions:
        print(tmp.transactions)


if __name__ == '__main__':
    main()

However, the test2 filter doesn't find any transaction that matches the transaction1 dictionary. 但是,test2筛选器找不到与transaction1字典匹配的任何事务。 I suspect this has to do with the fact that the dict are stored as MutableDict and not Dict. 我怀疑这与字典存储为MutableDict而不是Dict的事实有关。 But what do I do about that and how do I edit and change my transaction1 after I have added it. 但是,我要怎么做以及添加后如何编辑和更改transaction1。

TLDR: I want to change content in my dict that is stored as an ORM using SQLAlchemy. TLDR:我想更改我的字典中使用SQLAlchemy存储为ORM的内容。

I realised that I was able to work around my problem by simply not using the .filter method. 我意识到,不用使用.filter方法就可以解决我的问题。 Hence the example below works just fine. 因此,以下示例可以正常工作。

    transaction1 = {'item1': 'banana',
                    'item2': 'apple',
                    'item3': 'sugar',
                    'item4': 'coke',
                    'item5': 'candy'}
    transaction2 = {'item1': 'pizza',
                    'item2': 'water'}

    new_obj = Person(first_name='Bob', last_name='Smith')
    session.add(new_obj)

    new_transaction = Transactions(transactions=transaction1, person_object=new_obj)
    session.add(new_transaction)

    new_transaction = Transactions(transactions=transaction2, person_object=new_obj)
    session.add(new_transaction)
    session.commit()

    test = session.query(Transactions).all()

    for tmp in test:
        print(tmp.transactions)

    new_transaction.transactions['item1'] = 'curry banana'
    session.commit()

    test = session.query(Transactions).all()

    for tmp in test:
        print(tmp.transactions)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM