#36846: ContentType.get_object_for_this_type() does not handle removed models
-------------------------------------+-------------------------------------
     Reporter:  Maarten ter Huurne   |                    Owner:  Vishy
         Type:                       |  Algo
  Cleanup/optimization               |                   Status:  closed
    Component:                       |                  Version:  dev
  contrib.contenttypes               |
     Severity:  Normal               |               Resolution:  wontfix
     Keywords:                       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Comment (by Maarten ter Huurne):

 Maybe I should add some context to explain why I think this is an actual
 bug and not an API cleanup proposal:

 We have an application where samples can be registered taken from various
 kinds of goods. As those goods use different models, we use
 `GenericForeignKey` to link the sample to the good being sampled. At some
 point, I removed the models for some types of goods that we don't need
 anymore, but didn't remove the old samples. Then the admin site (made
 using `django.contrib.admin`) started crashing (uncaught exception on page
 generation) whenever a sample linking to a removed model was being
 displayed in an index table, because the lookup of the `GenericForeignKey`
 hit an unhandled `None` model.

 When `get_object_for_this_type()` raises `ObjectDoesNotExist`, the admin
 site will display "-" instead, which for this use case is the desired
 behavior. There is a subtle difference between the situation where all
 instances of a model have been removed and the model itself having been
 removed, but I'm not sure that distinction is important enough to require
 a separate exception. In what scenario would the caller of
 `get_object_for_this_type()` handle "model does not exist" differently
 from "instance does not exist"?

 If you insist on having separate exception types, having
 `get_object_for_this_type()` raise `LookupError` without changing
 `model_class()` would also be an option, as `model_class()` explicitly
 swallows `LookupError`:
 {{{#!python
 def model_class(self):
         """Return the model class for this type of content."""
         try:
             return apps.get_model(self.app_label, self.model)
         except LookupError:
             return None
 }}}
 So if `get_object_for_this_type()` would call `apps.get_model()` directly
 instead of going through `model_class()`, it would raise `LookupError` on
 removed models. This would avoid a deprecation cycle. However, the admin
 site would also have to be updated then to catch `LookupError` in addition
 to `ObjectDoesNotExist`.

 In any case, the current behavior of raising `AttributeError` seems like
 the worst alternative: it is not the right exception type and it's not
 documented either. In my opinion, any of the alternatives
 (`get_object_for_this_type()` raising `ObjectDoesNotExist`,
 `get_object_for_this_type()` raising `LookupError`, or `model_class()`
 raising `LookupError`) would be preferable over keeping the current
 behavior.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/36846#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/0107019b9d8e6dca-4f2a517e-007d-4836-9ac4-417f6d6c75dd-000000%40eu-central-1.amazonses.com.

Reply via email to