mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	[5.0.x] Fixed #34985 -- Fixed GeneratedFields.contribute_to_class() crash when apps are not populated.
Thanks Paolo Melchiorre for the report. Regression inf333e3513e. Backport of101a85a5a0from main
This commit is contained in:
		| @@ -13,7 +13,6 @@ class GeneratedField(Field): | ||||
|     db_returning = True | ||||
|  | ||||
|     _query = None | ||||
|     _resolved_expression = None | ||||
|     output_field = None | ||||
|  | ||||
|     def __init__(self, *, expression, output_field, db_persist=None, **kwargs): | ||||
| @@ -48,9 +47,6 @@ class GeneratedField(Field): | ||||
|         super().contribute_to_class(*args, **kwargs) | ||||
|  | ||||
|         self._query = Query(model=self.model, alias_cols=False) | ||||
|         self._resolved_expression = self.expression.resolve_expression( | ||||
|             self._query, allow_joins=False | ||||
|         ) | ||||
|         # Register lookups from the output_field class. | ||||
|         for lookup_name, lookup in self.output_field.get_class_lookups().items(): | ||||
|             self.register_lookup(lookup, lookup_name=lookup_name) | ||||
| @@ -59,7 +55,10 @@ class GeneratedField(Field): | ||||
|         compiler = connection.ops.compiler("SQLCompiler")( | ||||
|             self._query, connection=connection, using=None | ||||
|         ) | ||||
|         return compiler.compile(self._resolved_expression) | ||||
|         resolved_expression = self.expression.resolve_expression( | ||||
|             self._query, allow_joins=False | ||||
|         ) | ||||
|         return compiler.compile(resolved_expression) | ||||
|  | ||||
|     def check(self, **kwargs): | ||||
|         databases = kwargs.get("databases") or [] | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| from django.apps import apps | ||||
| from django.db import IntegrityError, connection | ||||
| from django.db.models import ( | ||||
|     CharField, | ||||
| @@ -33,6 +34,25 @@ class BaseGeneratedFieldTests(SimpleTestCase): | ||||
|                 db_persist=False, | ||||
|             ) | ||||
|  | ||||
|     @isolate_apps("model_fields") | ||||
|     def test_contribute_to_class(self): | ||||
|         class BareModel(Model): | ||||
|             pass | ||||
|  | ||||
|         new_field = GeneratedField( | ||||
|             expression=Lower("nonexistent"), | ||||
|             output_field=IntegerField(), | ||||
|             db_persist=True, | ||||
|         ) | ||||
|         apps.models_ready = False | ||||
|         try: | ||||
|             # GeneratedField can be added to the model even when apps are not | ||||
|             # fully loaded. | ||||
|             new_field.contribute_to_class(BareModel, "name") | ||||
|             self.assertEqual(BareModel._meta.get_field("name"), new_field) | ||||
|         finally: | ||||
|             apps.models_ready = True | ||||
|  | ||||
|     def test_blank_unsupported(self): | ||||
|         with self.assertRaisesMessage(ValueError, "GeneratedField must be blank."): | ||||
|             GeneratedField( | ||||
| @@ -217,10 +237,6 @@ class GeneratedFieldTestMixin: | ||||
|         db_parameters = field.db_parameters(connection) | ||||
|         self.assertEqual(db_parameters["collation"], collation) | ||||
|         self.assertEqual(db_parameters["type"], field.output_field.db_type(connection)) | ||||
|         self.assertNotEqual( | ||||
|             db_parameters["type"], | ||||
|             field._resolved_expression.output_field.db_type(connection), | ||||
|         ) | ||||
|  | ||||
|     def test_db_type_parameters(self): | ||||
|         db_type_parameters = self.output_field_db_collation_model._meta.get_field( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user