@@ -56,6 +56,26 @@ def permissions_allowed_for_system_role() -> dict[Type[Model], list[str]]:
5656 return permissions_by_model
5757
5858
59+ def get_descendent_models_from_db (main_ct : Model ):
60+ """For a given content type, get all content types from the database that reference them as a parent
61+
62+ Including any content types that reference a content type that reference this content type as a parent.
63+ """
64+ seen_ids = set ()
65+ result = []
66+ queue = [main_ct ]
67+
68+ while queue :
69+ current = queue .pop (0 )
70+ for child in current .child_content_types .all ():
71+ if child .pk not in seen_ids :
72+ seen_ids .add (child .pk )
73+ result .append (child )
74+ queue .append (child )
75+
76+ return result
77+
78+
5979def permissions_allowed_for_role (cls ) -> dict [Union [Type [Model ], Type [RemoteObject ]], list [str ]]:
6080 "Permission codenames valid for a RoleDefinition of given class, organized by permission class"
6181 if cls is None :
@@ -66,19 +86,21 @@ def permissions_allowed_for_role(cls) -> dict[Union[Type[Model], Type[RemoteObje
6686
6787 permissions_by_model = defaultdict (list )
6888
89+ # Warm cache to load all types and related permissions
90+ permission_registry .content_type_model .objects .warm_cache (permission_registry .content_type_model .objects .prefetch_related ('dab_permissions' ))
91+
92+ # Add direct model permissions
6993 cls_ct = permission_registry .content_type_model .objects .get_for_model (cls )
7094 for permission in cls_ct .dab_permissions .all ():
7195 if not is_add_perm (permission .codename ):
7296 permissions_by_model [cls ].append (permission .codename )
7397
7498 # Add permissions for all child types
75- for ct in cls_ct .child_content_types .prefetch_related ('dab_permissions' ):
76- for permission in ct .dab_permissions .prefetch_related ('content_type__child_content_types' ):
77- permissions_by_model [ct .model_class ()].append (permission .codename )
78- # Process grandchild models
79- for grandchild_ct in permission .content_type .child_content_types .all ():
80- for grandchild_perm in grandchild_ct .dab_permissions .all ():
81- permissions_by_model [grandchild_ct .model_class ()].append (grandchild_perm .codename )
99+ for ct in get_descendent_models_from_db (cls_ct ):
100+ for child_permission in ct .dab_permissions .all ():
101+ # Include add permissions for child models
102+ permissions_by_model [ct .model_class ()].append (child_permission .codename )
103+
82104 return permissions_by_model
83105
84106
0 commit comments