1

是否可以更改关联代理中引用的集合类的键?

例子:

class Event(ManagerBase):
    """Defines an event."""

    __tablename__ = 'eventing_events'

    id = Column(Integer, primary_key=True)
    device_id = Column(Integer, ForeignKey(EventingDevice.id), nullable=False)
    device = relation(EventingDevice)
    type_id = Column(Integer, ForeignKey(EventType.id), nullable=False)
    type = relation(EventType)
    datetime = Column(DateTime, nullable=False)
    summary = Column(String(500))

    fields = association_proxy("field_values", "value")

class EventFieldValue(ManagerBase):
    """The value of a single field of an event."""

    __tablename__ = 'eventing_event_field_values'

    event_id = Column(Integer, ForeignKey(Event.id), primary_key=True)
    event = relation(Event, backref=backref("field_values",
                                            collection_class=attribute_mapped_collection("field")))
    field_id = Column(Integer, ForeignKey(Field.id), primary_key=True)
    field = relation(Field)
    value = Column(Text)

在这种情况下, 的field属性Event将表示一个EventFieldValue.field作为键的字典。是否可以仅在代理本身中更改此密钥而不影响关系?

4

1 回答 1

1

似乎这对于原始 SQLAlchemy 是不可能的AssociationProxy,因为该类直接访问原始关系,因此任何键都将在基础关系上 1:1 查询。

我写了一个类DictProxy,它允许更改键和值字段:

class DictProxy(object):
    def __init__(self, col, keyattr, valattr = None):
        self.obj = None
        self.col = col
        self.keyattr = keyattr
        self.valattr = valattr

    def __get__(self, obj, class_):
        self.obj = obj
        return self

    def __repr__(self):
        outdict = {}
        for k, v in getattr(self.obj, self.col).iteritems():
            if not k is None:
                if self.valattr == None:
                    outdict[getattr(k, self.keyattr)] = v
                elif v is not None:
                    outdict[getattr(k, self.keyattr)] = getattr(v, self.valattr)
                else:
                    outdict[getattr(k, self.keyattr)] = None
        return repr(outdict)

    def __getitem__(self, key):
        keyobj = [obj for obj in getattr(self.obj, self.col) if getattr(obj, self.keyattr) == key]
        if not len(keyobj):
            return None
        if self.valattr == None:
            return getattr(self.obj, self.col)[keyobj[0]]
        else:
            return getattr(getattr(self.obj, self.col)[keyobj[0]], self.valattr)

    def __contains__(self, key):
        return len([obj for obj in getattr(self.obj, self.col) if getattr(obj, self.keyattr) == key]) != 0

def dict_proxy(*arg):
    return DictProxy(*arg)

示例用法:

class Event(ManagerBase):
    """Defines an event."""

    __tablename__ = 'eventing_events'

    id = Column(Integer, primary_key=True)
    device_id = Column(Integer, ForeignKey(EventingDevice.id), nullable=False)
    device = relation(EventingDevice)
    type_id = Column(Integer, ForeignKey(EventType.id), nullable=False)
    type = relation(EventType)
    datetime = Column(DateTime, nullable=False)
    summary = Column(String(500))

    fields = dict_proxy("field_values", "name", "value")

fieldsof Eventnow 是一个EventFieldValue.name作为键的字典,并访问关系 field_values (来自EventFieldValuevia backref)。

注意: 实际上这是一个只读代理,但可能(虽然很棘手)通过__setitem__方法扩展代理。

于 2012-06-26T17:34:02.680 回答