Как я могу использовать attribute_mapped_collection с defaultdict (список)? - PullRequest
0 голосов
/ 21 февраля 2019

Я пытаюсь использовать attribute_mapped_collection, который отображает атрибут в список объектов с этим атрибутом.

Чтобы объяснить это лучше, в Python я могу реализовать это так:

from collections import defaultdict

my_dict = defaultdict(list)

Каждый раз, когда я добавляю к определенному ключу, он просто создает список, который собирает элементы с одинаковым ключом.Таким образом, мы получаем

[ins] In [18]: my_dict = defaultdict(list)

[ins] In [19]: my_dict[1].append(1)

[nav] In [20]: my_dict[1].append(2)

[ins] In [21]: my_dict
Out[21]: defaultdict(list, {1: [1, 2]})

Это было бы невероятно полезно в sqlalchemy при следующих обстоятельствах:

class Node(Base):
    id = db.Column(db.Integer, primary_key=True)


class Attribute(Base):
    id = db.Column(db.Integer, primary_key=True)
    node_id = db.Column(db.Integer, db.ForeignKey('node.id'))
    node = db.relationship(
        'Node',
        backref=backref('attributes', collection_class='attribute_mapped_collection('node_attr')))

    node_attr = db.Column(db.String) # a string based keyword-attribute

Это работает фантастически , если все attributes имеют уникальные node_attr«s .Как только у нас есть повторы, мы сталкиваемся с ключами словаря, определенными последним совпадением node_attr.Каждое последующее значение с тем же ключом закрывает предыдущее значение.

Я бы хотел, чтобы отображаемый словарь Node.attributes был словарем атрибутов, сопоставленных со списками объектов, как в приведенном выше примере defaultdict.Как я могу это сделать?

Я пытаюсь пролистать документацию, чтобы найти простой способ использования defaultdict(list) вместо встроенного dict, но, похоже, мне нужно реализоватьспециальный MappedCollection класс .К сожалению, документация для этого чрезвычайно запутана, и я совсем не уверен, какие магические методы мне действительно нужно реализовать.Например, в связанном разделе я вижу это:

@collection.internally_instrumented
def __setitem__(self, key, value, _sa_initiator=None):
    # do something with key, value
    super(MyMappedCollection, self).__setitem__(key, value, _sa_initiator)

@collection.internally_instrumented
def __delitem__(self, key, _sa_initiator=None):
    # do something with key
    super(MyMappedCollection, self).__delitem__(key, _sa_initiator)

Но я понятия не имею, что такое _sa_initiator.Кроме того, в документации указывается:

class sqlalchemy.orm.collections.MappedCollection(keyfunc)¶

  Bases: builtins.dict

Что означает, что MappedCollection уже основан на builtin.dict и поэтому не может быть переопределен для моего варианта использования.

Указания в этомнаправление, если это направление, в котором я должен идти, было бы очень полезно.

Обновление

Я начал мошенничать с обходным путем.

Использование формы.reconstructor Я просто создаю defaultdict при загрузке объекта.Я не думаю, что это вызовет какие-либо проблемы с производительностью, поскольку фактический набор значений довольно мал, вообще говоря, но если есть способ сделать это с помощью SQLA, я бы очень хотел это знать.

...