mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #21893 -- ModelState didn't account for MTI parents inherited from abstract models.
This commit is contained in:
		| @@ -151,6 +151,23 @@ class ModelState(object): | |||||||
|                     options[name] = set(normalize_together(it)) |                     options[name] = set(normalize_together(it)) | ||||||
|                 else: |                 else: | ||||||
|                     options[name] = model._meta.original_attrs[name] |                     options[name] = model._meta.original_attrs[name] | ||||||
|  |  | ||||||
|  |         def flatten_bases(model): | ||||||
|  |             bases = [] | ||||||
|  |             for base in model.__bases__: | ||||||
|  |                 if hasattr(base, "_meta") and base._meta.abstract: | ||||||
|  |                     bases.extend(flatten_bases(base)) | ||||||
|  |                 else: | ||||||
|  |                     bases.append(base) | ||||||
|  |             return bases | ||||||
|  |  | ||||||
|  |         # We can't rely on __mro__ directly because we only want to flatten | ||||||
|  |         # abstract models and not the whole tree. However by recursing on | ||||||
|  |         # __bases__ we may end up with duplicates and ordering issues, we | ||||||
|  |         # therefore discard any duplicates and reorder the bases according | ||||||
|  |         # to their index in the MRO. | ||||||
|  |         flattened_bases = sorted(set(flatten_bases(model)), key=lambda x:model.__mro__.index(x)) | ||||||
|  |  | ||||||
|         # Make our record |         # Make our record | ||||||
|         bases = tuple( |         bases = tuple( | ||||||
|             ( |             ( | ||||||
| @@ -158,12 +175,11 @@ class ModelState(object): | |||||||
|                 if hasattr(base, "_meta") else |                 if hasattr(base, "_meta") else | ||||||
|                 base |                 base | ||||||
|             ) |             ) | ||||||
|             for base in model.__bases__ |             for base in flattened_bases | ||||||
|             if (not hasattr(base, "_meta") or not base._meta.abstract) |  | ||||||
|         ) |         ) | ||||||
|         # Ensure at least one base inherits from models.Model |         # Ensure at least one base inherits from models.Model | ||||||
|         if not any((isinstance(base, six.string_types) or issubclass(base, models.Model)) for base in bases): |         if not any((isinstance(base, six.string_types) or issubclass(base, models.Model)) for base in bases): | ||||||
|             bases = (models.Model, ) |             bases = (models.Model,) | ||||||
|         return cls( |         return cls( | ||||||
|             model._meta.app_label, |             model._meta.app_label, | ||||||
|             model._meta.object_name, |             model._meta.object_name, | ||||||
|   | |||||||
| @@ -166,6 +166,16 @@ class StateTests(TestCase): | |||||||
|                 app_label = "migrations" |                 app_label = "migrations" | ||||||
|                 apps = Apps() |                 apps = Apps() | ||||||
|  |  | ||||||
|  |         class AbstractSubFooBar(FooBar): | ||||||
|  |             class Meta: | ||||||
|  |                 abstract = True | ||||||
|  |                 apps = Apps() | ||||||
|  |  | ||||||
|  |         class SubFooBar(AbstractSubFooBar): | ||||||
|  |             class Meta: | ||||||
|  |                 app_label = "migrations" | ||||||
|  |                 apps = Apps() | ||||||
|  |  | ||||||
|         apps = Apps(["migrations"]) |         apps = Apps(["migrations"]) | ||||||
|  |  | ||||||
|         # We shouldn't be able to render yet |         # We shouldn't be able to render yet | ||||||
| @@ -175,8 +185,13 @@ class StateTests(TestCase): | |||||||
|  |  | ||||||
|         # Once the parent models are in the app registry, it should be fine |         # Once the parent models are in the app registry, it should be fine | ||||||
|         ModelState.from_model(Foo).render(apps) |         ModelState.from_model(Foo).render(apps) | ||||||
|  |         self.assertSequenceEqual(ModelState.from_model(Foo).bases, [models.Model]) | ||||||
|         ModelState.from_model(Bar).render(apps) |         ModelState.from_model(Bar).render(apps) | ||||||
|  |         self.assertSequenceEqual(ModelState.from_model(Bar).bases, [models.Model]) | ||||||
|         ModelState.from_model(FooBar).render(apps) |         ModelState.from_model(FooBar).render(apps) | ||||||
|  |         self.assertSequenceEqual(ModelState.from_model(FooBar).bases, ['migrations.foo', 'migrations.bar']) | ||||||
|  |         ModelState.from_model(SubFooBar).render(apps) | ||||||
|  |         self.assertSequenceEqual(ModelState.from_model(SubFooBar).bases, ['migrations.foobar']) | ||||||
|  |  | ||||||
|     def test_render_project_dependencies(self): |     def test_render_project_dependencies(self): | ||||||
|         """ |         """ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user