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