"Utilities for loading models and the modules that contain them." from django.conf import settings from django.core.exceptions import ImproperlyConfigured import sys import os __all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models') _app_list = [] # Cache of installed apps. # Entry is not placed in app_list cache until entire app is loaded. _app_models = {} # Dictionary of models against app label # Each value is a dictionary of model name: model class # Applabel and Model entry exists in cache when individual model is loaded. _app_errors = {} # Dictionary of errors that were experienced when loading the INSTALLED_APPS # Key is the app_name of the model, value is the exception that was raised # during model loading. _loaded = False # Has the contents of settings.INSTALLED_APPS been loaded? # i.e., has get_apps() been called? def get_apps(): "Returns a list of all installed modules that contain models." global _app_list global _loaded if not _loaded: _loaded = True for app_name in settings.INSTALLED_APPS: try: load_app(app_name) except Exception, e: # Problem importing the app _app_errors[app_name] = e return _app_list def get_app(app_label, emptyOK=False): "Returns the module containing the models for the given app_label. If the app has no models in it and 'emptyOK' is True, returns None." get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish. for app_name in settings.INSTALLED_APPS: if app_label == app_name.split('.')[-1]: mod = load_app(app_name) if mod is None: if emptyOK: return None else: return mod raise ImproperlyConfigured, "App with label %s could not be found" % app_label def load_app(app_name): "Loads the app with the provided fully qualified name, and returns the model module." global _app_list mod = __import__(app_name, {}, {}, ['models']) if not hasattr(mod, 'models'): return None if mod.models not in _app_list: _app_list.append(mod.models) return mod.models def get_app_errors(): "Returns the map of known problems with the INSTALLED_APPS" global _app_errors get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish. return _app_errors def get_models(app_mod=None): """ Given a module containing models, returns a list of the models. Otherwise returns a list of all installed models. """ app_list = get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish. if app_mod: return _app_models.get(app_mod.__name__.split('.')[-2], {}).values() else: model_list = [] for app_mod in app_list: model_list.extend(get_models(app_mod)) return model_list def get_model(app_label, model_name, seed_cache=True): """ Returns the model matching the given app_label and case-insensitive model_name. Returns None if no model is found. """ if seed_cache: get_apps() try: model_dict = _app_models[app_label] except KeyError: return None try: return model_dict[model_name.lower()] except KeyError: return None def register_models(app_label, *models): """ Register a set of models as belonging to an app. """ for model in models: # Store as 'name: model' pair in a dictionary # in the _app_models dictionary model_name = model._meta.object_name.lower() model_dict = _app_models.setdefault(app_label, {}) if model_dict.has_key(model_name): # The same model may be imported via different paths (e.g. # appname.models and project.appname.models). We use the source # filename as a means to detect identity. fname1 = os.path.abspath(sys.modules[model.__module__].__file__) fname2 = os.path.abspath(sys.modules[model_dict[model_name].__module__].__file__) # Since the filename extension could be .py the first time and .pyc # or .pyo the second time, ignore the extension when comparing. if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]: continue model_dict[model_name] = model