Python SQLAlchemy:如何通过事件侦听器有条件地添加到集合?
在sqlalchemy中,我可以监听集合上的Python SQLAlchemy:如何通过事件侦听器有条件地添加到集合?,python,sqlalchemy,Python,Sqlalchemy,在sqlalchemy中,我可以监听集合上的append事件,以拦截并可能更改要追加的值。例如,当我想用任意条件实现类似于集的行为时,如何静默地删除该值(而不是追加) MCVE(除了sqlalchemy,没有任何依赖项,只需复制和粘贴): 在这里回答我自己,因为没有人感兴趣 我现在认为,在添加事件侦听器时删除元素是不可能的。因此,我最终实现了一个(这并不是很受鼓励的),结果是非常简单的: from sqlalchemy import create_engine, Integer, Text fr
append
事件,以拦截并可能更改要追加的值。例如,当我想用任意条件实现类似于集的行为时,如何静默地删除该值(而不是追加)
MCVE(除了sqlalchemy,没有任何依赖项,只需复制和粘贴):
在这里回答我自己,因为没有人感兴趣
我现在认为,在添加事件侦听器时删除元素是不可能的。因此,我最终实现了一个(这并不是很受鼓励的),结果是非常简单的:
from sqlalchemy import create_engine, Integer, Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.schema import Column, ForeignKey
engine = create_engine('sqlite:///:memory:')
Base = declarative_base()
_next_id = 1
def get_id():
global _next_id
_ = _next_id
_next_id += 1
return _
class NamedThingCollection(object):
def __init__(self):
self.data = []
def __contains__(self, thing):
return next((True for x in self.data if x.name == thing.name), False)
def append(self, item):
if item not in self:
self.data.append(item)
def remove(self, item):
self.data.remove(item)
def extend(self, items):
self.data.extend(items)
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
class A1(Base):
__tablename__ = 'a1'
id = Column(Integer, primary_key=True, default=get_id)
a2 = relationship(
'A2', back_populates='a', collection_class=NamedThingCollection)
class A2(Base):
__tablename__ = 'a2'
id = Column(Integer, primary_key=True, default=get_id)
a_id = Column(Integer, ForeignKey('a1.id'))
a = relationship('A1', back_populates='a2')
name = Column(Text)
Base.metadata.create_all(engine)
Session = sessionmaker()
Session.configure(bind=engine)
_session = Session()
a2_1 = A2(name='a2_1')
a2_2 = A2(name='a2_2')
a2_3 = A2(name='a2_1')
a1 = A1()
for thing in (a2_1, a2_2, a2_3, a1):
_session.add(thing)
for a in (a2_1, a2_2, a2_3, a2_1):
a1.a2.append(a)
_session.flush()
assert len(a1.a2) == 2
当然,用户必须根据需要实现进一步的行为,例如用于索引的\uuu getitem\uuuuuuuuuu()
/\uuuuuuuu setitem\uuuuuuuuu()
from sqlalchemy import create_engine, Integer, Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.schema import Column, ForeignKey
engine = create_engine('sqlite:///:memory:')
Base = declarative_base()
_next_id = 1
def get_id():
global _next_id
_ = _next_id
_next_id += 1
return _
class NamedThingCollection(object):
def __init__(self):
self.data = []
def __contains__(self, thing):
return next((True for x in self.data if x.name == thing.name), False)
def append(self, item):
if item not in self:
self.data.append(item)
def remove(self, item):
self.data.remove(item)
def extend(self, items):
self.data.extend(items)
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
class A1(Base):
__tablename__ = 'a1'
id = Column(Integer, primary_key=True, default=get_id)
a2 = relationship(
'A2', back_populates='a', collection_class=NamedThingCollection)
class A2(Base):
__tablename__ = 'a2'
id = Column(Integer, primary_key=True, default=get_id)
a_id = Column(Integer, ForeignKey('a1.id'))
a = relationship('A1', back_populates='a2')
name = Column(Text)
Base.metadata.create_all(engine)
Session = sessionmaker()
Session.configure(bind=engine)
_session = Session()
a2_1 = A2(name='a2_1')
a2_2 = A2(name='a2_2')
a2_3 = A2(name='a2_1')
a1 = A1()
for thing in (a2_1, a2_2, a2_3, a1):
_session.add(thing)
for a in (a2_1, a2_2, a2_3, a2_1):
a1.a2.append(a)
_session.flush()
assert len(a1.a2) == 2