Fixes #20587: Handle stale ContentTypes in has_feature()

When deleting stale ContentTypes during remove_stale_contenttypes, the
pre_delete signal triggers notify_object_changed(), which calls
has_feature() with the ContentType instance. For stale types (those with
no corresponding model class), model_class() returns None, which then gets
passed to issubclass() in the feature test lambda, causing a TypeError.

The previous implementation in has_feature() checked for None before
attempting ObjectType lookup. The optimization in 5ceb6a6 removed this
safety check when refactoring the ContentType code path to use direct
feature registry lookups. This restores the null check to maintain the
original behavior of returning False for stale ContentTypes.
This commit is contained in:
Jason Novinger 2025-10-15 12:27:14 -05:00 committed by Jeremy Stretch
parent addda0538f
commit 2ae98f0353

View File

@ -676,6 +676,8 @@ def has_feature(model_or_ct, feature):
# If a ContentType was passed, resolve its model class and run the associated feature test # If a ContentType was passed, resolve its model class and run the associated feature test
elif type(model_or_ct) is ContentType: elif type(model_or_ct) is ContentType:
model = model_or_ct.model_class() model = model_or_ct.model_class()
if model is None: # Stale content type
return False
try: try:
test_func = registry['model_features'][feature] test_func = registry['model_features'][feature]
except KeyError: except KeyError: