How to write a django orm-like module?

I am trying to write a orm package which source data is json, First I created a Department class (I am trying to mimic django model)

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})>"

Then I created Organization class as a search manager.

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

My expected result is:

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

But I have no idea how to achieve it, can anybody help me?


Solution 1:

If you want to access the parent object instance by class attribute you have to declare it in the Department class:

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})>"

Then in your Organization class you can write a new method that searchs for the parent data and sets the attribute before returning it:

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

Then you can access the parent attribute like you're expecting:

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

EDIT: That snippet only gets the first parent in the hierarchy. If you want to get all children from any node then you must rewrite the _get_parent function to be recursive:

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

Now you can access all the parent objects from any node:

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