mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.7.x] Implement Migration.run_before
This attribute (used for reverse dependencies) was previously declared and mentioned in the code, but never actually used.
This commit is contained in:
		
				
					committed by
					
						 Andrew Godwin
						Andrew Godwin
					
				
			
			
				
	
			
			
			
						parent
						
							31fc34e447
						
					
				
				
					commit
					9f1c4e4d3f
				
			| @@ -134,6 +134,25 @@ class MigrationLoader(object): | ||||
|         else: | ||||
|             return self.disk_migrations[results[0]] | ||||
|  | ||||
|     def check_key(self, key, current_app): | ||||
|         if key[1] != "__first__" or key in self.graph: | ||||
|             return key | ||||
|         # Special-case __first__, which means "the first migration" for | ||||
|         # migrated apps, and is ignored for unmigrated apps. It allows | ||||
|         # makemigrations to declare dependencies on apps before they even have | ||||
|         # migrations. | ||||
|         if key[0] == current_app: | ||||
|             # Ignore __first__ references to the same app (#22325) | ||||
|             return | ||||
|         if key[0] in self.unmigrated_apps: | ||||
|             # This app isn't migrated, but something depends on it. | ||||
|             # The models will get auto-added into the state, though | ||||
|             # so we're fine. | ||||
|             return | ||||
|         if key[0] in self.migrated_apps: | ||||
|             return list(self.graph.root_nodes(key[0]))[0] | ||||
|         raise ValueError("Dependency on unknown app %s" % key[0]) | ||||
|  | ||||
|     def build_graph(self): | ||||
|         """ | ||||
|         Builds a migration dependency graph using both the disk and database. | ||||
| @@ -196,25 +215,13 @@ class MigrationLoader(object): | ||||
|             self.graph.add_node(key, migration) | ||||
|         for key, migration in normal.items(): | ||||
|             for parent in migration.dependencies: | ||||
|                 # Special-case __first__, which means "the first migration" for | ||||
|                 # migrated apps, and is ignored for unmigrated apps. It allows | ||||
|                 # makemigrations to declare dependencies on apps before they | ||||
|                 # even have migrations. | ||||
|                 if parent[1] == "__first__" and parent not in self.graph: | ||||
|                     if parent[0] == key[0]: | ||||
|                         # Ignore __first__ references to the same app (#22325) | ||||
|                         continue | ||||
|                     elif parent[0] in self.unmigrated_apps: | ||||
|                         # This app isn't migrated, but something depends on it. | ||||
|                         # The models will get auto-added into the state, though | ||||
|                         # so we're fine. | ||||
|                         continue | ||||
|                     elif parent[0] in self.migrated_apps: | ||||
|                         parent = list(self.graph.root_nodes(parent[0]))[0] | ||||
|                     else: | ||||
|                         raise ValueError("Dependency on unknown app %s" % parent[0]) | ||||
|                 parent = self.check_key(parent, key[0]) | ||||
|                 if parent is not None: | ||||
|                     self.graph.add_dependency(key, parent) | ||||
|             for child in migration.run_before: | ||||
|                 child = self.check_key(child, key[0]) | ||||
|                 if child is not None: | ||||
|                     self.graph.add_dependency(child, key) | ||||
|  | ||||
|     def detect_conflicts(self): | ||||
|         """ | ||||
|   | ||||
| @@ -102,6 +102,22 @@ class LoaderTests(TestCase): | ||||
|             ["id", "user"] | ||||
|         ) | ||||
|  | ||||
|     @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_run_before"}) | ||||
|     def test_run_before(self): | ||||
|         """ | ||||
|         Makes sure the loader uses Migration.run_before. | ||||
|         """ | ||||
|         # Load and test the plan | ||||
|         migration_loader = MigrationLoader(connection) | ||||
|         self.assertEqual( | ||||
|             migration_loader.graph.forwards_plan(("migrations", "0002_second")), | ||||
|             [ | ||||
|                 ("migrations", "0001_initial"), | ||||
|                 ("migrations", "0003_third"), | ||||
|                 ("migrations", "0002_second"), | ||||
|             ], | ||||
|         ) | ||||
|  | ||||
|     @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}) | ||||
|     def test_name_match(self): | ||||
|         "Tests prefix name matching" | ||||
|   | ||||
							
								
								
									
										20
									
								
								tests/migrations/test_migrations_run_before/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								tests/migrations/test_migrations_run_before/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     operations = [ | ||||
|  | ||||
|         migrations.CreateModel( | ||||
|             "Salamander", | ||||
|             [ | ||||
|                 ("id", models.AutoField(primary_key=True)), | ||||
|                 ("size", models.IntegerField(default=0)), | ||||
|                 ("silly_field", models.BooleanField(default=False)), | ||||
|             ], | ||||
|         ), | ||||
|  | ||||
|     ] | ||||
							
								
								
									
										23
									
								
								tests/migrations/test_migrations_run_before/0002_second.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								tests/migrations/test_migrations_run_before/0002_second.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ("migrations", "0001_initial"), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|  | ||||
|         migrations.CreateModel( | ||||
|             "Book", | ||||
|             [ | ||||
|                 ("id", models.AutoField(primary_key=True)), | ||||
|                 ("author", models.ForeignKey("migrations.Author", null=True)), | ||||
|             ], | ||||
|         ) | ||||
|  | ||||
|     ] | ||||
							
								
								
									
										32
									
								
								tests/migrations/test_migrations_run_before/0003_third.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/migrations/test_migrations_run_before/0003_third.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|     """ | ||||
|     This is a wee bit crazy, but it's just to show that run_before works. | ||||
|     """ | ||||
|  | ||||
|     dependencies = [ | ||||
|         ("migrations", "0001_initial"), | ||||
|     ] | ||||
|  | ||||
|     run_before = [ | ||||
|         ("migrations", "0002_second"), | ||||
|     ] | ||||
|  | ||||
|     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)), | ||||
|             ], | ||||
|         ) | ||||
|  | ||||
|     ] | ||||
		Reference in New Issue
	
	Block a user