Ticket #21719: 21719-postponing-wip.patch

File 21719-postponing-wip.patch, 8.4 KB (added by Aymeric Augustin, 10 years ago)
  • django/apps/registry.py

    diff --git a/django/apps/registry.py b/django/apps/registry.py
    index 41095bd..913cc4b 100644
    a b from django.utils import lru_cache  
    99from django.utils.deprecation import RemovedInDjango19Warning
    1010from django.utils._os import upath
    1111
    12 from .config import AppConfig
     12from .config import AppConfig, MODELS_MODULE_NAME
    1313
    1414
    1515class Apps(object):
    class Apps(object):  
    4848        # Lock for thread-safe population.
    4949        self._lock = threading.Lock()
    5050
     51        # Models imported before their apps.
     52        self._orphan_models = []
     53
    5154        # Pending lookups for lazy relations.
    5255        self._pending_lookups = {}
    5356
    class Apps(object):  
    100103                    "Application names aren't unique, "
    101104                    "duplicates: %s" % ", ".join(duplicates))
    102105
     106            # Handle models loaded prematurely.
     107            orphan_models, self._orphan_models = self._orphan_models, None
     108            for orphan_model in orphan_models:
     109                self.register_model(orphan_model)
     110
    103111            # Load models.
    104112            for app_config in self.app_configs.values():
    105113                all_models = self.all_models[app_config.label]
    class Apps(object):  
    189197            app_label, model_name = app_label.split('.')
    190198        return self.get_app_config(app_label).get_model(model_name.lower())
    191199
    192     def register_model(self, app_label, model):
     200    def register_model(self, model):
    193201        # Since this method is called when models are imported, it cannot
    194202        # perform imports because of the risk of import loops. It mustn't
    195203        # call get_app_config().
     204        if model._meta.app_label is None:
     205            app_config = self.get_containing_app_config(model.__module__)
     206        else:
     207            app_config = self.app_configs.get(model._meta.app_label)
     208
     209        if app_config is None:
     210            if self._orphan_models is not None:
     211                # Applications are still loading. Orphaning is allowed.
     212                self._orphan_models.append(model)
     213                return
     214            else:
     215                # If the model isn't in an installed application (#21680), use
     216                # the legacy logic to figure out the app_label by looking one
     217                # level up from the package or module named 'models'. If no
     218                # such package or module exists, fall back to looking one
     219                # level up from the module this model is defined in.
     220
     221                # For 'django.contrib.sites.models', this would be 'sites'.
     222                # For 'geo.models.places' this would be 'geo'.
     223
     224                msg = (
     225                    "Model class %s.%s doesn't declare an explicit app_label "
     226                    "and either isn't in an application in INSTALLED_APPS. " %
     227                    (model.__module__, model.__name__))
     228                if model._meta.abstract:
     229                    msg += "Its app_label will be set to None in Django 1.9."
     230                else:
     231                    msg += "This will no longer be supported in Django 1.9."
     232                warnings.warn(msg, RemovedInDjango19Warning, stacklevel=2)
     233
     234                package_components = model.__module__.split('.')
     235                package_components.reverse()  # find the last occurrence of 'models'
     236                try:
     237                    app_label_index = package_components.index(MODELS_MODULE_NAME) + 1
     238                except ValueError:
     239                    app_label_index = 1
     240                model._meta.app_label = package_components[app_label_index]
     241        else:
     242            model._meta.app_label = app_config.label
     243
    196244        model_name = model._meta.model_name
    197         app_models = self.all_models[app_label]
     245        app_models = self.all_models[model._meta.app_label]
    198246        if model_name in app_models:
    199247            raise RuntimeError(
    200248                "Conflicting '%s' models in application '%s': %s and %s." %
    class Apps(object):  
    416464            "register_models(app_label, *models) is deprecated.",
    417465            RemovedInDjango19Warning, stacklevel=2)
    418466        for model in models:
    419             self.register_model(app_label, model)
     467            self.register_model(model)
    420468
    421469
    422470apps = Apps(installed_apps=None)
  • django/db/models/base.py

    diff --git a/django/db/models/base.py b/django/db/models/base.py
    index ba89e6e..1e5f57a 100644
    a b class ModelBase(type):  
    8989            meta = attr_meta
    9090        base_meta = getattr(new_class, '_meta', None)
    9191
    92         # Look for an application configuration to attach the model to.
    93         app_config = apps.get_containing_app_config(module)
    94 
    95         if getattr(meta, 'app_label', None) is None:
    96 
    97             if app_config is None:
    98                 # If the model is imported before the configuration for its
    99                 # application is created (#21719), or isn't in an installed
    100                 # application (#21680), use the legacy logic to figure out the
    101                 # app_label by looking one level up from the package or module
    102                 # named 'models'. If no such package or module exists, fall
    103                 # back to looking one level up from the module this model is
    104                 # defined in.
    105 
    106                 # For 'django.contrib.sites.models', this would be 'sites'.
    107                 # For 'geo.models.places' this would be 'geo'.
    108 
    109                 msg = (
    110                     "Model class %s.%s doesn't declare an explicit app_label "
    111                     "and either isn't in an application in INSTALLED_APPS or "
    112                     "else was imported before its application was loaded. " %
    113                     (module, name))
    114                 if abstract:
    115                     msg += "Its app_label will be set to None in Django 1.9."
    116                 else:
    117                     msg += "This will no longer be supported in Django 1.9."
    118                 warnings.warn(msg, RemovedInDjango19Warning, stacklevel=2)
    119 
    120                 model_module = sys.modules[new_class.__module__]
    121                 package_components = model_module.__name__.split('.')
    122                 package_components.reverse()  # find the last occurrence of 'models'
    123                 try:
    124                     app_label_index = package_components.index(MODELS_MODULE_NAME) + 1
    125                 except ValueError:
    126                     app_label_index = 1
    127                 kwargs = {"app_label": package_components[app_label_index]}
    128 
    129             else:
    130                 kwargs = {"app_label": app_config.label}
    131 
    132         else:
    133             kwargs = {}
     92        new_class.add_to_class('_meta', Options(meta))
     93        new_class._meta.apps.register_model(new_class)
    13494
    135         new_class.add_to_class('_meta', Options(meta, **kwargs))
    13695        if not abstract:
    13796            new_class.add_to_class(
    13897                'DoesNotExist',
    class ModelBase(type):  
    293252            # little differently from normal models.
    294253            attr_meta.abstract = False
    295254            new_class.Meta = attr_meta
    296             return new_class
     255        else:
     256            new_class._prepare()
    297257
    298         new_class._prepare()
    299         new_class._meta.apps.register_model(new_class._meta.app_label, new_class)
    300258        return new_class
    301259
    302260    def copy_managers(cls, base_managers):
  • django/db/models/options.py

    diff --git a/django/db/models/options.py b/django/db/models/options.py
    index d204bcf..cfbbb8b 100644
    a b from django.db.models.fields.related import ManyToManyRel  
    1010from django.db.models.fields import AutoField, FieldDoesNotExist
    1111from django.db.models.fields.proxy import OrderWrt
    1212from django.utils import six
    13 from django.utils.deprecation import RemovedInDjango18Warning
     13from django.utils.deprecation import RemovedInDjango18Warning, RemovedInDjango19Warning
    1414from django.utils.encoding import force_text, smart_text, python_2_unicode_compatible
    1515from django.utils.functional import cached_property
    1616from django.utils.text import camel_case_to_spaces
    def normalize_together(option_together):  
    4949
    5050@python_2_unicode_compatible
    5151class Options(object):
     52
    5253    def __init__(self, meta, app_label=None):
     54        if app_label is not None:
     55            warnings.warn(
     56                "The app_label argument of Options is deprecated.",
     57                RemovedInDjango19Warning, stacklevel=2)
    5358        self.local_fields = []
    5459        self.local_many_to_many = []
    5560        self.virtual_fields = []
Back to Top