#31357: Stale content types can cause exception in ContentType.get_for_models
------------------------------------------------+------------------------
Reporter: Andy Chosak | Owner: nobody
Type: Bug | Status: new
Component: contrib.contenttypes | Version: 3.0
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
------------------------------------------------+------------------------
`ContentType.get_for_models`
([[https://github.com/django/django/blob/e3e48b00127c09eafe6439d980a82fc5c591b673/django/contrib/contenttypes/models.py#L62|source]])
retrieves content types from the database for a given list of models. Due
to the way this method works, it's possible to trigger an unexpected
`AttributeError` by passing in a list of models whose `(app_label,
model_name)` pairs can be permuted to refer to a model with a stale
content type in the database.
Consider this example:
1. A project has an app named `foo` with models named `Author` and `Book`.
Content types for these exist in the database.
2. A new app named `bar` is created providing an alternate `Book` model.
The content type for this also exists.
3. The model `foo.Book` is deleted. The database is migrated, but the
stale content type is left behind.
The following code will raise an exception:
{{{
>> from foo.models import Author
>>> from bar.models import Book
>>> from django.contrib.contenttypes.models import ContentType
>>> ContentType.objects.get_for_models(Author, Book)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/path/to/myproject/lib/python3.6/site-
packages/django/contrib/contenttypes/models.py", line 89, in
get_for_models
opts_models = needed_opts.pop(ct.model_class()._meta, [])
AttributeError: 'NoneType' object has no attribute '_meta'
}}}
This occurs because the `ct.model_class()` call returns `None` for stale
content types.
The problem is in
[[https://github.com/django/django/blob/e3e48b00127c09eafe6439d980a82fc5c591b673/django/contrib/contenttypes/models.py#L83-L87|this
database lookup]] that tries to pull back content types for the models
that were passed in. Instead of pulling back only the `ContentType`
instances for those models, it filters by
`app_label__in=needed_app_labels, model__in=needed_models`. For the above
case, this pulls back not just `(foo, Author)` and `(bar, Book)` but also
`(foo, Book)`, which in this case is stale.
A fix here could either alter the query to be more specific or check the
returned content types to make sure they correspond to one of the desired
models.
--
Ticket URL: <https://code.djangoproject.com/ticket/31357>
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 on the web visit
https://groups.google.com/d/msgid/django-updates/049.3305fe724694aecb20bfedd09d6af4b0%40djangoproject.com.