#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 [email protected].
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.

Reply via email to