diff options
| author | Andrew Godwin <andrew@aeracode.org> | 2013-09-06 12:14:09 -0500 |
|---|---|---|
| committer | Andrew Godwin <andrew@aeracode.org> | 2013-09-06 12:16:03 -0500 |
| commit | cdeff3acc2b7d77b7f309db7e98878e08ad9ff25 (patch) | |
| tree | b0b4707ec72465390e7859c9c9f349cfeadfc341 /django | |
| parent | 6f7977bb63ea592faaa7b3bdf2898f8361f30260 (diff) | |
Project/ModelState now correctly serialize multi-model inheritance
Diffstat (limited to 'django')
| -rw-r--r-- | django/db/migrations/state.py | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/django/db/migrations/state.py b/django/db/migrations/state.py index f4e0325472..0e532d3fdc 100644 --- a/django/db/migrations/state.py +++ b/django/db/migrations/state.py @@ -1,9 +1,14 @@ from django.db import models from django.db.models.loading import BaseAppCache from django.db.models.options import DEFAULT_NAMES +from django.utils import six from django.utils.module_loading import import_by_path +class InvalidBasesError(ValueError): + pass + + class ProjectState(object): """ Represents the entire project's overall state. @@ -28,8 +33,21 @@ class ProjectState(object): "Turns the project state into actual models in a new AppCache" if self.app_cache is None: self.app_cache = BaseAppCache() - for model in self.models.values(): - model.render(self.app_cache) + # We keep trying to render the models in a loop, ignoring invalid + # base errors, until the size of the unrendered models doesn't + # decrease by at least one, meaning there's a base dependency loop/ + # missing base. + unrendered_models = list(self.models.values()) + while unrendered_models: + new_unrendered_models = [] + for model in unrendered_models: + try: + model.render(self.app_cache) + except InvalidBasesError: + new_unrendered_models.append(model) + if len(new_unrendered_models) == len(unrendered_models): + raise InvalidBasesError("Cannot resolve bases for %r" % new_unrendered_models) + unrendered_models = new_unrendered_models return self.app_cache @classmethod @@ -86,7 +104,11 @@ class ModelState(object): else: options[name] = model._meta.original_attrs[name] # Make our record - bases = tuple(model for model in model.__bases__ if (not hasattr(model, "_meta") or not model._meta.abstract)) + bases = tuple( + ("%s.%s" % (base._meta.app_label, base._meta.object_name.lower()) if hasattr(base, "_meta") else base) + for base in model.__bases__ + if (not hasattr(base, "_meta") or not base._meta.abstract) + ) if not bases: bases = (models.Model, ) return cls( @@ -123,7 +145,12 @@ class ModelState(object): meta_contents["unique_together"] = list(meta_contents["unique_together"]) meta = type("Meta", tuple(), meta_contents) # Then, work out our bases - # TODO: Use the actual bases + bases = tuple( + (app_cache.get_model(*base.split(".", 1)) if isinstance(base, six.string_types) else base) + for base in self.bases + ) + if None in bases: + raise InvalidBasesError("Cannot resolve one or more bases from %r" % self.bases) # Turn fields into a dict for the body, add other bits body = dict(self.fields) body['Meta'] = meta @@ -131,7 +158,7 @@ class ModelState(object): # Then, make a Model object return type( self.name, - tuple(self.bases), + bases, body, ) |
