mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #33174 -- Fixed migrations crash for model inheriting from Generic[T].
This commit is contained in:
		
				
					committed by
					
						 Sarah Boyce
						Sarah Boyce
					
				
			
			
				
	
			
			
			
						parent
						
							8be0c0d690
						
					
				
				
					commit
					825ddda26a
				
			| @@ -1,4 +1,5 @@ | ||||
| import copy | ||||
| import typing | ||||
| from collections import defaultdict | ||||
| from contextlib import contextmanager | ||||
| from functools import partial | ||||
| @@ -969,6 +970,7 @@ class ModelState: | ||||
|             bases = tuple( | ||||
|                 (apps.get_model(base) if isinstance(base, str) else base) | ||||
|                 for base in self.bases | ||||
|                 if base != typing.Generic | ||||
|             ) | ||||
|         except LookupError: | ||||
|             raise InvalidBasesError( | ||||
|   | ||||
| @@ -0,0 +1,40 @@ | ||||
| import typing | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|     initial = True | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name="GenericModel", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "id", | ||||
|                     models.AutoField( | ||||
|                         auto_created=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         verbose_name="ID", | ||||
|                     ), | ||||
|                 ), | ||||
|             ], | ||||
|             bases=(typing.Generic, models.Model), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name="GenericModelPEP695", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "id", | ||||
|                     models.AutoField( | ||||
|                         auto_created=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         verbose_name="ID", | ||||
|                     ), | ||||
|                 ), | ||||
|             ], | ||||
|             bases=(models.Model, typing.Generic), | ||||
|         ), | ||||
|     ] | ||||
| @@ -0,0 +1,31 @@ | ||||
| from django.db import migrations, models | ||||
|  | ||||
| from ..models import Child | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ("with_generic_model", "0001_initial"), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name="CustomGenericModel", | ||||
|             fields=[ | ||||
|                 ( | ||||
|                     "id", | ||||
|                     models.AutoField( | ||||
|                         auto_created=True, | ||||
|                         primary_key=True, | ||||
|                         serialize=False, | ||||
|                         verbose_name="ID", | ||||
|                     ), | ||||
|                 ), | ||||
|             ], | ||||
|             bases=( | ||||
|                 Child, | ||||
|                 models.Model, | ||||
|             ), | ||||
|         ), | ||||
|     ] | ||||
| @@ -0,0 +1,36 @@ | ||||
| import typing | ||||
|  | ||||
| from django.db import models | ||||
|  | ||||
| T = typing.TypeVar("T") | ||||
|  | ||||
|  | ||||
| class GenericModel(typing.Generic[T], models.Model): | ||||
|     """A model inheriting from typing.Generic.""" | ||||
|  | ||||
|  | ||||
| class GenericModelPEP695[T](models.Model): | ||||
|     """A model inheriting from typing.Generic via the PEP 695 syntax.""" | ||||
|  | ||||
|  | ||||
| # Example from Python docs: | ||||
| # https://typing.python.org/en/latest/spec/generics.html#arbitrary-generic-types-as-base-classes | ||||
| T1 = typing.TypeVar("T1") | ||||
| T2 = typing.TypeVar("T2") | ||||
| T3 = typing.TypeVar("T3") | ||||
|  | ||||
|  | ||||
| class Parent1(typing.Generic[T1, T2]): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class Parent2(typing.Generic[T1, T2]): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class Child(Parent1[T1, T3], Parent2[T2, T3]): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class CustomGenericModel(Child[T1, T3, T2], models.Model): | ||||
|     """A model inheriting from a custom subclass of typing.Generic.""" | ||||
| @@ -1551,6 +1551,14 @@ class MigrateTests(MigrationTestBase): | ||||
|             recorder.record_unapplied("migrations2", "0002_second") | ||||
|             recorder.record_unapplied("migrations2", "0001_squashed_0002") | ||||
|  | ||||
|     @override_settings( | ||||
|         INSTALLED_APPS=[ | ||||
|             "migrations.migrations_test_apps.with_generic_model", | ||||
|         ] | ||||
|     ) | ||||
|     def test_migrate_model_inherit_generic(self): | ||||
|         call_command("migrate", verbosity=0) | ||||
|  | ||||
|  | ||||
| class MakeMigrationsTests(MigrationTestBase): | ||||
|     """ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user