#34816: GenericForeignKey crashes if content_type_id is changed and object_id is type incompatible with old object ------------------------------------------------+------------------------ Reporter: Richard Laager | Owner: nobody Type: Uncategorized | Status: new Component: contrib.contenttypes | Version: 4.2 Severity: Normal | Keywords: Triage Stage: Unreviewed | Has patch: 1 Needs documentation: 0 | Needs tests: 0 Patch needs improvement: 0 | Easy pickings: 0 UI/UX: 0 | ------------------------------------------------+------------------------ Steps to reproduce:
1. Create a model ("A") with a GenericForeignKey. 2. Create an instance of A ("a") referencing an instance of model "B" with a PK that is an integer type. 3. Change the instance of "A" to reference an instance of model "C" with a PK that is incompatible with int(). But make this change using `content_type_id` and `object_id` properties, not `content_object`, i.e.: {{{#!python a.content_type_id = ContentType.objects.get_for_model(B) a.object_id = "foo" }}} 4. Try to access `a.content_object`. Expected result: This looks up and returns an instance of "b" (the B with a PK of "foo"). Actual result: This crashes (I'm using 3.2, but the code is unchanged in master): {{{#!python File "django/db/models/fields/__init__.py", line 1836, in to_python return int(value) ValueError: invalid literal for int() with base 10: 'foo' }}} This happens because it tries to `to_python()` the new key on the old model's PK field. One possible fix would be to make the logic short-circuit, like this (also attached): {{{#!diff diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index 35fcd0d908..e984fb5375 100644 --- a/django/contrib/contenttypes/fields.py +++ b/django/contrib/contenttypes/fields.py @@ -242,11 +242,11 @@ class GenericForeignKey(FieldCacheMixin): ct_match = ( ct_id == self.get_content_type(obj=rel_obj, using=instance._state.db).id ) - pk_match = rel_obj._meta.pk.to_python(pk_val) == rel_obj.pk - if ct_match and pk_match: - return rel_obj - else: - rel_obj = None + if ct_match: + pk_match = rel_obj._meta.pk.to_python(pk_val) == rel_obj.pk + if pk_match: + return rel_obj + rel_obj = None if ct_id is not None: ct = self.get_content_type(id=ct_id, using=instance._state.db) try: }}} -- Ticket URL: <https://code.djangoproject.com/ticket/34816> 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 django-updates+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/0107018a6ce5348a-a3e393d6-c052-4502-9117-2602c7a41b17-000000%40eu-central-1.amazonses.com.