""" These functions handle the adding of fields to other models """ from django.db.models import FieldDoesNotExist, ForeignKey, ManyToManyField from . import fields # from settings import self._field_registry, self._model_registry from django.utils.translation import ugettext_lazy as _ from django.core.exceptions import ImproperlyConfigured FIELD_TYPES = { 'ForeignKey': ForeignKey, 'ManyToManyField': ManyToManyField, } class Registry(object): def __init__(self): self._field_registry = {} self._model_registry = {} def register_model(self, app, model_name, field_type, field_definitions): """ Process for Django 1.7 + app: app name/label model_name: name of the model field_definitions: a string, tuple or list of field configurations field_type: either 'ForeignKey' or 'ManyToManyField' """ from django.apps import apps import collections app_label = app if isinstance(field_definitions, str): field_definitions = [field_definitions] elif not isinstance(field_definitions, collections.Iterable): raise ImproperlyConfigured(_('Field configuration for %(app)s should be a string or iterable') % {'app': app}) if field_type not in ('ForeignKey', 'ManyToManyField'): raise ImproperlyConfigured(_('`field_type` must be either `"ForeignKey"` or `"ManyToManyField"`.')) try: if not hasattr(model_name, "_meta"): app_config = apps.get_app_config(app) app_label = app_config.label model = app_config.get_model(model_name) else: model = model_name model_name = model._meta.model_name opts = model._meta if app_label not in self._model_registry: self._model_registry[app_label] = [] if model not in self._model_registry[app_label]: self._model_registry[app_label].append(model) except LookupError: raise ImproperlyConfigured('Model "%(model)s" doesn\'t exist in app "%(app)s".' % {'model': model_name, 'app': app}) if not isinstance(field_definitions, (tuple, list)): field_definitions = [field_definitions] for fld in field_definitions: extra_params = {'to': 'categories.Category', 'blank': True} if field_type != 'ManyToManyField': extra_params['null'] = True if isinstance(fld, str): field_name = fld elif isinstance(fld, dict): if 'name' in fld: field_name = fld.pop('name') else: continue extra_params.update(fld) else: raise ImproperlyConfigured( _("%(settings)s doesn't recognize the value of %(app)s.%(model)s") % { 'settings': 'CATEGORY_SETTINGS', 'app': app, 'model': model_name}) registry_name = ".".join([app_label, model_name.lower(), field_name]) if registry_name in self._field_registry: continue try: opts.get_field(field_name) except FieldDoesNotExist: self._field_registry[registry_name] = FIELD_TYPES[field_type](**extra_params) self._field_registry[registry_name].contribute_to_class(model, field_name) def register_m2m(self, model, field_name='categories', extra_params={}): return self._register(model, field_name, extra_params, fields.CategoryM2MField) def register_fk(self, model, field_name='category', extra_params={}): return self._register(model, field_name, extra_params, fields.CategoryFKField) def _register(self, model, field_name, extra_params={}, field=fields.CategoryFKField): app_label = model._meta.app_label registry_name = ".".join((app_label, model.__name__, field_name)).lower() if registry_name in self._field_registry: return # raise AlreadyRegistered opts = model._meta try: opts.get_field(field_name) except FieldDoesNotExist: if app_label not in self._model_registry: self._model_registry[app_label] = [] if model not in self._model_registry[app_label]: self._model_registry[app_label].append(model) self._field_registry[registry_name] = field(**extra_params) self._field_registry[registry_name].contribute_to_class(model, field_name) registry = Registry() def _process_registry(registry, call_func): """ Given a dictionary, and a registration function, process the registry """ from django.core.exceptions import ImproperlyConfigured from django.apps import apps for key, value in list(registry.items()): model = apps.get_model(*key.split('.')) if model is None: raise ImproperlyConfigured(_('%(key)s is not a model') % {'key': key}) if isinstance(value, (tuple, list)): for item in value: if isinstance(item, str): call_func(model, item) elif isinstance(item, dict): field_name = item.pop('name') call_func(model, field_name, extra_params=item) else: raise ImproperlyConfigured(_("%(settings)s doesn't recognize the value of %(key)s") % {'settings': 'CATEGORY_SETTINGS', 'key': key}) elif isinstance(value, str): call_func(model, value) elif isinstance(value, dict): field_name = value.pop('name') call_func(model, field_name, extra_params=value) else: raise ImproperlyConfigured(_("%(settings)s doesn't recognize the value of %(key)s") % {'settings': 'CATEGORY_SETTINGS', 'key': key})