""" App management for djinit. Handles creation of Django apps and updating settings. """ import os import subprocess from typing import Optional from src.scripts.console_ui import UIFormatter from src.scripts.template_engine import template_engine from src.utils import create_file_with_content class AppManager: def __init__(self, app_name: str): self.app_name = app_name self.current_dir = os.getcwd() self.manage_py_path = os.path.join(self.current_dir, "manage.py") def create_app(self) -> bool: if not self._is_django_project(): UIFormatter.print_error( "Not in a Django project directory. Please run this command from your Django project root." ) return False if self._app_exists(): UIFormatter.print_error(f"Django app '{self.app_name}' already exists.") return False if not self._create_django_app(): return False if not self._add_to_installed_apps(): return False if not self._create_additional_files(): return False UIFormatter.print_success(f"Django app '{self.app_name}' created and configured successfully!") return True def _is_django_project(self) -> bool: return os.path.exists(self.manage_py_path) def _app_exists(self) -> bool: app_path = os.path.join(self.current_dir, self.app_name) return os.path.exists(app_path) def _create_django_app(self) -> bool: result = subprocess.run(["django-admin", "startapp", self.app_name], capture_output=True, text=True, check=True) UIFormatter.print_success(f"Created Django app '{self.app_name}'") return True def _add_to_installed_apps(self) -> bool: settings_path = self._find_settings_path() if not settings_path: UIFormatter.print_error("Could not find Django settings directory") return False base_settings_path = os.path.join(settings_path, "base.py") if not os.path.exists(base_settings_path): UIFormatter.print_error("Could not find base.py settings file") return False with open(base_settings_path) as f: content = f.read() if f'"{self.app_name}"' in content or f"'{self.app_name}'" in content: UIFormatter.print_info(f"App '{self.app_name}' is already in INSTALLED_APPS") return True if "USER_DEFINED_APPS" not in content: UIFormatter.print_error("Could not find USER_DEFINED_APPS section in base.py") return False lines = content.split("\n") new_lines = [] in_user_apps = False apps_added = False for line in lines: if "USER_DEFINED_APPS" in line and "=" in line: in_user_apps = True new_lines.append(line) elif in_user_apps and line.strip() == "]": new_lines.append(f' "{self.app_name}",') new_lines.append(line) in_user_apps = False apps_added = True else: new_lines.append(line) if not apps_added: UIFormatter.print_error("Could not find USER_DEFINED_APPS section in base.py") return False with open(base_settings_path, "w") as f: f.write("\n".join(new_lines)) UIFormatter.print_success(f"Added '{self.app_name}' to USER_DEFINED_APPS in base.py") return True def _find_settings_path(self) -> Optional[str]: # Look for project directories that contain settings for item in os.listdir(self.current_dir): if os.path.isdir(item) and not item.startswith(".") and item != "__pycache__": # Check if this directory contains Django project files project_path = os.path.join(self.current_dir, item) settings_path = os.path.join(project_path, "settings") # Check if settings directory exists with base.py if os.path.exists(settings_path) and os.path.exists(os.path.join(settings_path, "base.py")): return settings_path # Fallback: look for settings in current directory settings_path = os.path.join(self.current_dir, "settings") if os.path.exists(settings_path) and os.path.exists(os.path.join(settings_path, "base.py")): return settings_path return None def _create_additional_files(self) -> bool: """Create additional files for the app (serializers.py, routes.py).""" app_path = os.path.join(self.current_dir, self.app_name) # Create serializers.py context = {"app_name": self.app_name} serializers_content = template_engine.render_template("serializers.j2", context) if not create_file_with_content( os.path.join(app_path, "serializers.py"), serializers_content, f"Created {self.app_name}/serializers.py", should_format=True, ): return False # Create routes.py routes_content = template_engine.render_template("routes.j2", context) if not create_file_with_content( os.path.join(app_path, "routes.py"), routes_content, f"Created {self.app_name}/routes.py", should_format=True, ): return False return True