在python

时间:2016-11-08 18:55:17

标签: python json mongodb dictionary casting

我知道之前已经回答了类似的问题,但在花了几个小时浏览网页后,我仍然无法正确解决我的问题(或'python-way'解决方案)

我正在使用以下'数据库'模块将任何对象插入MongoDB:

from pymongo import MongoClient
import json

def insert(obj, collection_name):
    with MongoClient(27017, 'localhost') as client:
        if hasattr(obj, '__dict__'):
            doc = obj.__dict__
        else:
            doc = json.dumps(obj)
        return client['test'][collection_name].insert_one(doc).inserted_id

def get_one(collection_name, query):
    with MongoClient(27017, 'localhost') as client:
        return client['test'][collection_name].find_one(query)

这部分很有效,因为我可以处理任何模块中的任何类并以通用方式存储对象。

我面临的问题是从MongoDB重新加载一个对象并将其强制转换回正确的类。

我有一个通用类'Operation'(表示可以对银行/资金帐户执行的操作:

import database 

class Operation(object):
    def __init__(self):
        self._id = 'OPE-{}'.format(str(uuid.uuid1()))

    @property
    def id(self):
        return self._id

    def save(self):
        database.update(self, 'operations')

def create_from_dict(d):
    operation = Operation()
    for key, value in d.items():
        operation.__dict__[key] = value
    return operation

def get(operation_id):
    return create_from_dict(database.get_one('operations', {'_id': operation_id}))

在此之前一切正常,我可以实例化任何Operation对象,将其插入MongoDB并使用它的id加载回来。

现在我有两个新课程'费用'和'学分'来自'操作'

import uuid
from operation import Operation

class Credit(Operation):
    def __init__(self):
        Operation.__init__(self)
        self._id = 'CRE-{}'.format(uuid.uuid1())

    @property
    def id(self):
        return self._id

import uuid
from operation import Operation

class Fee(Operation):
    def __init__(self):
        Operation.__init__(self)
        self._id = 'FEE-{}'.format(uuid.uuid1())

    @property
    def id(self):
        return self._id

我们的想法是保留代码以保存/加载'Operation'类中的对象,并在需要时创建简单的派生类。 所以'Operation'类应该能够动态地将加载的对象从Operation转换为Credit / Fee / Transfer ......

我尝试做的是在所有类上添加以下行以存储对象类型:

self.type = self.__class__

或者(因为类不能直接序列化为json)

self.type = self.__name__

但我不知道如何实现:

def create_from_dict(d):
    operation = Operation()
    for key, value in d.items():
        operation.__dict__[key] = value
    operation.__class__ = get_type_from_name(operation.type) #This is the function I'm trying to implement
    return operation

在编码对象时,是否应该存储模块和类名,以便从另一个模块中将其强制转换?

很抱歉这个问题很长,但我想完整地描述我的代码背后的逻辑 任何建议我都很开放!

编辑: locals()或globals()可以成为现实吗?您将类名传递给get_type_from_name()方法并返回相应的类? 对于优秀的Python主义者来说还有一个问题:这是正确的方法吗?

2 个答案:

答案 0 :(得分:1)

使用您建议的self.type = self.__name__提示,您可以尝试get_type_from_name函数的此实现:

def get_type_from_name(name):
    name_to_type = {'Credit': Credit, 'Fee':Fee}
    return name_to_type[name]

我不太确定我是否完全理解你的问题,所以请告诉我这是不是你想要的。

答案 1 :(得分:0)

我认为我设法让它发挥作用:

将此添加到我想要(de)序列化的类:

self.type = self.__class__.__name__
self.module = self.__module__

然后从PyMongo加载json doc:

    if not hasattr(doc, 'module') or not hasattr(doc, 'type'):
        return obj
    for key, value in doc.items():
        obj.__dict__[key] = value
    mod = __import__(obj.module, fromlist=[obj.type])
    obj.__class__ = getattr(mod, obj.type)

最后两行导入包含该类的模块,并动态修改对象 class

感谢user3030010的回答。 但我仍然很想知道你们是否认为这是一个好的设计,或者可能导致更多的问题。