首页 > 解决方案 > 如何编写类似 django orm 的模块?

问题描述

我正在尝试编写一个源数据为 json 的 orm 包,首先我创建了一个 Department 类(我试图模仿 django 模型)

class Department():
def __init__(self, data_dict):
    self.id = data_dict['id']
    self.organization_name = data_dict['organization_name']

def __str__(self):
    return f"<{self.__class__.__name__}(id={self.id})>"

然后我创建了组织类作为搜索管理器。

class Organization():
    data = [{
            "id": 1,
            "parent_id": 0,
            "organization_name": "President Office"
        },{
            "id": 2,
            "parent_id": 1,
            "organization_name": "Business Development Dept."
        },{
            "id": 3,
            "parent_id": 2,
            "organization_name": "Product Design Dept."
        }]
    def get(self,id):
        department_instance = None
        for department_dict in self.data:
            if department_dict['id'] == id:
                department_instance = Department(department_dict)
                break
    
        return department_instance

我的预期结果是:

org = Organization()
business_dev_dep = org.get(id=2) # <Department(id=2)>
business_dev_dep.parent_id # <Department(id=1)>

但我不知道如何实现它,有人可以帮助我吗?

标签: pythonpython-3.x

解决方案


如果你想通过类属性访问父对象实例,你必须在 Department 类中声明它:

class Department(object):
    def __init__(self, data_dict):
        self.id = data_dict['id']
        self.parent_id = None
        self.organization_name = data_dict['organization_name']

    def __str__(self):
        return f"<{self.__class__.__name__}(id={self.id})>"

然后在您的Organization类中,您可以编写一个新方法来搜索父数据并在返回之前设置属性:

class Organization(object):
    data = [{
        "id": 1,
        "parent_id": 0,
        "organization_name": "President Office"
    }, {
        "id": 2,
        "parent_id": 1,
        "organization_name": "Business Development Dept."
    }, {
        "id": 3,
        "parent_id": 2,
        "organization_name": "Product Design Dept."
    }]

    def _get_parent(self, parent_id):
        # id == 0 means that the object doesn't have parent?
        if parent_id > 0 and parent_id in map(lambda x: x['parent_id'], self.data):
            parent_data = list(filter(lambda x: x['id'] == parent_id, self.data)).pop()
            return Department(parent_data)

    def get(self, id):
        department_instance = None
        for department_dict in self.data:
            if department_dict['id'] == id:
                department_instance = Department(department_dict)
                department_instance.parent_id = self._get_parent(department_dict['parent_id'])
                break
        return department_instance

然后你可以像你期望的那样访问父属性:

org = Organization()
business_dev_dep = org.get(id=2) # <Department(id=2)>
business_dev_dep.parent_id

编辑:该片段仅获得层次结构中的第一个父级。如果要从任何节点获取所有子节点,则必须将_get_parent函数重写为递归:

class Organization(object):
    data = [{
        "id": 1,
        "parent_id": 0,
        "organization_name": "President Office"
    }, {
        "id": 2,
        "parent_id": 1,
        "organization_name": "Business Development Dept."
    }, {
        "id": 3,
        "parent_id": 2,
        "organization_name": "Product Design Dept."
    }]

def _get_parent(self, parent_id):
    # id == 0 means that the object doesn't have parent?
    if parent_id > 0 and parent_id in map(lambda x: x['parent_id'], self.data):
        parent_data = list(filter(lambda x: x['id'] == parent_id, self.data)).pop()
        parent = Department(parent_data)
        parent.parent_id = self._get_parent(parent_data['parent_id'])
        return parent

    def get(self, id):
        department_instance = None
        for department_dict in self.data:
            if department_dict['id'] == id:
                department_instance = Department(department_dict)
                department_instance.parent_id = self._get_parent(department_dict['parent_id'])
                break
        return department_instance

现在您可以从任何节点访问所有父对象:

org = Organization()
business_dev_dep = org.get(id=3)
print(business_dev_dep.parent_id.parent_id)
<Department(id=1)>

推荐阅读