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