I currently this code working, but its performance is very poor — 1.45 seconds seems a bit too much for a simple recursive if statement that only checks attribute values.
def _check_delete_status(self, obj) -> bool:
obj_name = obj._sa_class_manager.class_.__name__
self.visited.append(obj_name)
if getattr(obj, 'status', 'deleted').lower() != 'deleted':
children = [parent for parent in self._get_parents(self._get_table_by_table_name(obj_name)) if parent not in self.visited]
for child in children:
if (child_obj := getattr(obj, child, None)) and child not in self.visited:
if self._check_delete_status(child_obj):
return True
else:
return True
return False
Although self._get_parents
seems like a counterintuitive name (it's used elsewhere in the code), in this case it is still very useful to this solution: It returns a list with all possible attribute names that object might have as children. For example, an object named appointment
will have ['patient', 'schedule']
as response; of which patient
will have []
since it doesn't have any children, and schedule
will have ['physiotherapist', 'address', 'patient', 'service']
returned.
When those values are then used on getattr(object, child_name)
it returns the object corresponding to the child.
I tried to think on how to do this iteratively, but couldn't up come with any solutions.
PS: The reason for the self.visited
list, is that sometimes an object might have the exact same object nested inside, and since they have the same values they can be skipped.
EDIT: The "helper" methods:
def _get_table_by_table_name(self, table_name: str) -> Table:
return self._all_models[table_name]['table']
@staticmethod
def _get_parents(table: Table) -> set:
parents = set()
if table.foreign_keys:
for fk in table.foreign_keys:
parent_name = fk.column.table.name
parents.add(parent_name) if parent_name != table.name else None
return parents