Как сохранить объект Python в pymongo?(т.е. какой метод / возвращаемое значение мне нужно переопределить) - PullRequest
0 голосов
/ 29 марта 2019

Допустим, у меня есть класс: TestClass. Этот класс имеет слоты.

class TestClass(object):
    __slots__ = ('_id', 'value1', 'value2',)

Итак, мы создаем объект.

test = TestClass()
test.key1 = 'val1'
test.key2 = 'val2'

Отлично! Теперь я хотел бы вставить test в экземпляр MongoDB.

db.test_collection.insert(test)

Э-э-э.

TypeError: 'TestClass' object is not iterable

Хорошо, давайте сделаем это итеративно.

class TestClass(object):
    __slots__ = ('_id', 'key1', 'key2',)

    def __iter__(self):
        yield from dict(
            (slot, self.__getattribute__(slot))
            for slot in self.__slots__).items()

test = TestClass()
test.key1 = 'val1'
test.key2 = 'val2'

for i in test:
    print(i)

// result
// ('key1', 'val1')
// ('key2', 'val2')

db.test_collection.insert(test)

Это дает мне: doc['_id'] = ObjectId() // TypeError: 'tuple' object does not support item assignment.

Далее, скажем, у меня есть композиция объектов ...

test = TestClass()
test.key1 = 'val1'
test.key2 = TestClass()

Может ли кодировщик pymongo кодировать test.key2 при сохранении test?

РЕДАКТИРОВАТЬ: Хорошо, я не сохраняю объект напрямую и не вызываю функцию на объекте, такую ​​как test.to_document(), но цель состоит в том, чтобы составные поля (например, test.key2) стали диктовкой, так что что это может быть сохранено.

Ответы [ 2 ]

0 голосов
/ 30 марта 2019

Поскольку вы пытаетесь вставить отдельный объект, а не их серию, первое полученное вами сообщение об ошибке, предполагающее, что PyMongo ожидает итерацию, возможно, вводит в заблуждение.insert может принимать либо один документ (словарь), либо итерируемый из них.

Вы можете преобразовать объект в dict с помощью функции , подобной этой :

def slotted_to_dict(obj):
    return {s: getattr(obj, s) for s in obj.__slots__ if hasattr(obj, s)}

Тогда

db.test_collection.insert(slotted_to_dict(test))

должно работать, но это осуждается .Так что

db.test_collection.insert_one(slotted_to_dict(test))

, вероятно, лучше.

Обратите внимание, что если вы часто конвертируете объект со слотами в диктовку, то вы можете потерять любое преимущество в производительности от использования слотов.Кроме того, атрибут «_id» не будет установлен в тестовом объекте, и вам может потребоваться неудобное решение, подобное этому, чтобы сохранить идентификатор:

test._id = db.test_collection.insert_one(slotted_to_dict(test))
0 голосов
/ 29 марта 2019

Сначала я хотел бы спросить себя, почему важно хранить объект, как в Mongodb.Чего я хочу достичь здесь?

Если ответ на поставленный выше вопрос: «Да, для этого есть веская причина».Способ хранения объектов состоит в том, чтобы сначала сериализовать их, а затем сохранить эту сериализацию.

Модуль рассола сделает это за вас.

import pickle

test = TestClass()
dumped = pickle.dumps(test)
db.objects.insert_one({"data": dumped, "name": 'test'})

Стоит отметить, что, поскольку это объекты Python, и если пользователь в любом случае имеет возможность вставить протравленный объект в базу данных, и вы в какой-то момент открепите этот объект, это создаст угрозу безопасности.вы.

...