import importlib from collections import defaultdict from .registry import model_registry from .models import BaseModel, SideStoreModel import random import string import logging logger = logging.getLogger(__name__) def build_serializer_class(model_name): # Remove the 's' character at the end if present if model_name.endswith('s') and not model_name.endswith('ss'): model_name = model_name[:-1] # Capitalize words separated by a dash words = model_name.split('-') capitalized_words = [word[0].upper() + word[1:] for word in words] transformed_string = ''.join(capitalized_words) # Add 'Serializer' at the end transformed_string += 'Serializer' # Try to find serializer in current directory first try: module = importlib.import_module('api.serializers') return getattr(module, transformed_string) except (ImportError, AttributeError): module = importlib.import_module('.serializers', package=__package__) return getattr(module, transformed_string) def get_serializer(instance, model_name): serializer = build_serializer_class(model_name) return serializer(instance) def get_data(model_name, model_id): model = model_registry.get_model(model_name) return model.objects.get(id=model_id) def get_serialized_data_by_id(model_name, model_id): # print(f'model_name = {model_name}') model = model_registry.get_model(model_name) # logger.info(f'model for {model_name} = {model}') instance = model.objects.get(id=model_id) serializer = get_serializer(instance, model_name) return serializer.data def generate_random_id(length=8): return ''.join(random.choices(string.ascii_letters + string.digits, k=length)) class HierarchyOrganizer: def __init__(self): self.levels = [] # List of dictionaries, each representing a level self.item_levels = {} # Keep track of items and their levels: (model_name, id) -> level self.children = set() def add_item(self, model_name, item_data, level): """ Add an item to a specific level, ensuring it's at the highest level if already exists """ item_key = (model_name, item_data['model_id']) # If item exists at a lower level, remove it existing_level = self.item_levels.get(item_key) if existing_level is not None: if existing_level < level: # Keep the lower level (deeper in hierarchy) return # Remove from existing level self.levels[existing_level][model_name] = [ item for item in self.levels[existing_level].get(model_name, []) if item['model_id'] != item_data['model_id'] ] # Ensure we have enough levels while len(self.levels) <= level: self.levels.append(defaultdict(list)) # Add item to the appropriate level if model_name not in self.levels[level]: self.levels[level][model_name] = [] self.levels[level][model_name].append(item_data) self.item_levels[item_key] = level def get_organized_data(self): """ Return the organized levels, cleaning up empty models/levels """ # Clean up empty models and levels cleaned_levels = [] for level_dict in self.levels: cleaned_dict = {k: v for k, v in level_dict.items() if v} if cleaned_dict: cleaned_levels.append(cleaned_dict) return cleaned_levels def add_relations(self, instance): self.add_related_parents(instance) self.add_related_children(instance) def add_related_children(self, instance): self.children = instance.get_shared_children(set()) def grouped_children(self): grouped = defaultdict(list) for instance in self.children: class_name = instance.__class__.__name__ grouped[class_name].append(instance.data_identifier_dict()) return dict(grouped) def add_related_parents(self, instance, current_level=0): """ Recursively add all parents of an instance to the hierarchy organizer. Parents are added at a higher level than their children. """ parent_models = instance.get_parents_by_model() for parent_model_name, parent in parent_models.items(): if isinstance(parent, BaseModel): store_id = None if isinstance(parent, SideStoreModel): store_id = parent.store_id parent_data = { 'model_id': parent.id, 'store_id': store_id } # Add parent at the next level # print(f'*** add parent: {parent_model_name}: {parent.id}') self.add_item(parent_model_name, parent_data, current_level + 1) # Recursively process parent's parents self.add_related_parents(parent, current_level + 1)