mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Thanks to bendavis78 for the test and diagnostic work.
This commit is contained in:
		| @@ -44,11 +44,13 @@ class ProjectState(object): | ||||
|             # Any apps in self.real_apps should have all their models included | ||||
|             # in the render. We don't use the original model instances as there | ||||
|             # are some variables that refer to the Apps object. | ||||
|             # FKs/M2Ms from real apps are also not included as they just | ||||
|             # mess things up with partial states (due to lack of dependencies) | ||||
|             real_models = [] | ||||
|             for app_label in self.real_apps: | ||||
|                 app = global_apps.get_app_config(app_label) | ||||
|                 for model in app.get_models(): | ||||
|                     real_models.append(ModelState.from_model(model)) | ||||
|                     real_models.append(ModelState.from_model(model, exclude_rels=True)) | ||||
|             # Populate the app registry with a stub for each application. | ||||
|             app_labels = set(model_state.app_label for model_state in self.models.values()) | ||||
|             self.apps = Apps([AppConfigStub(label) for label in sorted(self.real_apps + list(app_labels))]) | ||||
| @@ -155,13 +157,15 @@ class ModelState(object): | ||||
|                 ) | ||||
|  | ||||
|     @classmethod | ||||
|     def from_model(cls, model): | ||||
|     def from_model(cls, model, exclude_rels=False): | ||||
|         """ | ||||
|         Feed me a model, get a ModelState representing it out. | ||||
|         """ | ||||
|         # Deconstruct the fields | ||||
|         fields = [] | ||||
|         for field in model._meta.local_fields: | ||||
|             if getattr(field, "rel", None) and exclude_rels: | ||||
|                 continue | ||||
|             name, path, args, kwargs = field.deconstruct() | ||||
|             field_class = import_string(path) | ||||
|             try: | ||||
| @@ -173,6 +177,7 @@ class ModelState(object): | ||||
|                     model._meta.object_name, | ||||
|                     e, | ||||
|                 )) | ||||
|         if not exclude_rels: | ||||
|             for field in model._meta.local_many_to_many: | ||||
|                 name, path, args, kwargs = field.deconstruct() | ||||
|                 field_class = import_string(path) | ||||
|   | ||||
| @@ -0,0 +1,30 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     operations = [ | ||||
|  | ||||
|         migrations.CreateModel( | ||||
|             "Author", | ||||
|             [ | ||||
|                 ("id", models.AutoField(primary_key=True)), | ||||
|                 ("name", models.CharField(max_length=255)), | ||||
|                 ("slug", models.SlugField(null=True)), | ||||
|                 ("age", models.IntegerField(default=0)), | ||||
|                 ("silly_field", models.BooleanField(default=False)), | ||||
|             ], | ||||
|         ), | ||||
|  | ||||
|         migrations.CreateModel( | ||||
|             "Tribble", | ||||
|             [ | ||||
|                 ("id", models.AutoField(primary_key=True)), | ||||
|                 ("fluffy", models.BooleanField(default=True)), | ||||
|             ], | ||||
|         ) | ||||
|  | ||||
|     ] | ||||
| @@ -0,0 +1,22 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     operations = [ | ||||
|  | ||||
|         migrations.CreateModel( | ||||
|             "OtherAuthor", | ||||
|             [ | ||||
|                 ("id", models.AutoField(primary_key=True)), | ||||
|                 ("name", models.CharField(max_length=255)), | ||||
|                 ("slug", models.SlugField(null=True)), | ||||
|                 ("age", models.IntegerField(default=0)), | ||||
|                 ("silly_field", models.BooleanField(default=False)), | ||||
|             ], | ||||
|         ), | ||||
|  | ||||
|     ] | ||||
| @@ -0,0 +1,12 @@ | ||||
| from django.db import models | ||||
|  | ||||
|  | ||||
| class OtherAuthor(models.Model): | ||||
|     id = models.AutoField(primary_key=True) | ||||
|     name = models.CharField(max_length=255) | ||||
|     slug = models.SlugField(null=True) | ||||
|     age = models.IntegerField(default=0) | ||||
|     silly_field = models.BooleanField(default=False) | ||||
|  | ||||
|     class Meta: | ||||
|         app_label = "migrated_unapplied_app" | ||||
| @@ -0,0 +1,9 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| from django.db import models | ||||
|  | ||||
|  | ||||
| class SillyModel(models.Model): | ||||
|     silly_field = models.BooleanField(default=False) | ||||
|     silly_tribble = models.ForeignKey("migrations.Tribble") | ||||
|     is_trouble = models.BooleanField(default=True) | ||||
| @@ -102,6 +102,29 @@ class MigrateTests(MigrationTestBase): | ||||
|         call_command("sqlmigrate", "migrations", "0001", stdout=stdout, backwards=True) | ||||
|         self.assertIn("drop table", stdout.getvalue().lower()) | ||||
|  | ||||
|     @override_system_checks([]) | ||||
|     @override_settings( | ||||
|         INSTALLED_APPS=[ | ||||
|             "migrations.migrations_test_apps.migrated_app", | ||||
|             "migrations.migrations_test_apps.migrated_unapplied_app", | ||||
|             "migrations.migrations_test_apps.unmigrated_app"]) | ||||
|     def test_regression_22823_unmigrated_fk_to_migrated_model(self): | ||||
|         """ | ||||
|         https://code.djangoproject.com/ticket/22823 | ||||
|  | ||||
|         Assuming you have 3 apps, `A`, `B`, and `C`, such that: | ||||
|  | ||||
|         * `A` has migrations | ||||
|         * `B` has a migration we want to apply | ||||
|         * `C` has no migrations, but has an FK to `A` | ||||
|  | ||||
|         When we try to migrate "B", an exception occurs because the | ||||
|         "B" was not included in the ProjectState that is used to detect | ||||
|         soft-applied migrations. | ||||
|         """ | ||||
|         stdout = six.StringIO() | ||||
|         call_command("migrate", "migrated_unapplied_app", stdout=stdout) | ||||
|  | ||||
|  | ||||
| class MakeMigrationsTests(MigrationTestBase): | ||||
|     """ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user