#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.

Reply via email to