@@ -37,6 +37,14 @@ def _get_current_field_from_assignment(ctx: FunctionContext, django_context: Dja
3737 return current_field
3838
3939
40+ def reparametrize_related_field_type (related_field_type : Instance , set_type , get_type ) -> Instance :
41+ args = [
42+ helpers .convert_any_to_type (related_field_type .args [0 ], set_type ),
43+ helpers .convert_any_to_type (related_field_type .args [1 ], get_type ),
44+ ]
45+ return helpers .reparametrize_instance (related_field_type , new_args = args )
46+
47+
4048def fill_descriptor_types_for_related_field (ctx : FunctionContext , django_context : DjangoContext ) -> MypyType :
4149 current_field = _get_current_field_from_assignment (ctx , django_context )
4250 if current_field is None :
@@ -48,6 +56,25 @@ def fill_descriptor_types_for_related_field(ctx: FunctionContext, django_context
4856 if related_model_cls is None :
4957 return AnyType (TypeOfAny .from_error )
5058
59+ default_related_field_type = set_descriptor_types_for_field (ctx )
60+
61+ # self reference with abstract=True on the model where ForeignKey is defined
62+ current_model_cls = current_field .model
63+ if (current_model_cls ._meta .abstract
64+ and current_model_cls == related_model_cls ):
65+ # for all derived non-abstract classes, set variable with this name to
66+ # __get__/__set__ of ForeignKey of derived model
67+ for model_cls in django_context .all_registered_model_classes :
68+ if issubclass (model_cls , current_model_cls ) and not model_cls ._meta .abstract :
69+ derived_model_info = helpers .lookup_class_typeinfo (helpers .get_typechecker_api (ctx ), model_cls )
70+ if derived_model_info is not None :
71+ fk_ref_type = Instance (derived_model_info , [])
72+ derived_fk_type = reparametrize_related_field_type (default_related_field_type ,
73+ set_type = fk_ref_type , get_type = fk_ref_type )
74+ helpers .add_new_sym_for_info (derived_model_info ,
75+ name = current_field .name ,
76+ sym_type = derived_fk_type )
77+
5178 related_model = related_model_cls
5279 related_model_to_set = related_model_cls
5380 if related_model_to_set ._meta .proxy_for_model is not None :
@@ -69,13 +96,10 @@ def fill_descriptor_types_for_related_field(ctx: FunctionContext, django_context
6996 else :
7097 related_model_to_set_type = Instance (related_model_to_set_info , []) # type: ignore
7198
72- default_related_field_type = set_descriptor_types_for_field (ctx )
7399 # replace Any with referred_to_type
74- args = [
75- helpers .convert_any_to_type (default_related_field_type .args [0 ], related_model_to_set_type ),
76- helpers .convert_any_to_type (default_related_field_type .args [1 ], related_model_type ),
77- ]
78- return helpers .reparametrize_instance (default_related_field_type , new_args = args )
100+ return reparametrize_related_field_type (default_related_field_type ,
101+ set_type = related_model_to_set_type ,
102+ get_type = related_model_type )
79103
80104
81105def get_field_descriptor_types (field_info : TypeInfo , is_nullable : bool ) -> Tuple [MypyType , MypyType ]:
0 commit comments