Opened 15 months ago
Last modified 14 months ago
#34816 closed Bug
GenericForeignKey crashes if content_type_id is changed and object_id is type incompatible with old object — at Initial Version
Reported by: | Richard Laager | Owned by: | nobody |
---|---|---|---|
Component: | contrib.contenttypes | Version: | 4.2 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Steps to reproduce:
- Create a model ("A") with a GenericForeignKey.
- Create an instance of A ("a") referencing an instance of model "B" with a PK that is an integer type.
- 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
andobject_id
properties, notcontent_object
, i.e.:a.content_type_id = ContentType.objects.get_for_model(B) a.object_id = "foo"
- 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):
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):
-
django/contrib/contenttypes/fields.py
diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index 35fcd0d908..e984fb5375 100644
a b class GenericForeignKey(FieldCacheMixin): 242 242 ct_match = ( 243 243 ct_id == self.get_content_type(obj=rel_obj, using=instance._state.db).id 244 244 ) 245 pk_match = rel_obj._meta.pk.to_python(pk_val) == rel_obj.pk246 if ct_match and pk_match:247 return rel_obj248 else:249 245 if ct_match: 246 pk_match = rel_obj._meta.pk.to_python(pk_val) == rel_obj.pk 247 if pk_match: 248 return rel_obj 249 rel_obj = None 250 250 if ct_id is not None: 251 251 ct = self.get_content_type(id=ct_id, using=instance._state.db) 252 252 try:
Note:
See TracTickets
for help on using tickets.