#34819: GenericForeignKey.get_prefetch_queryset() --------------------------------------+------------------------------------ Reporter: Richard Laager | Owner: nobody Type: Bug | Status: new Component: contrib.contenttypes | Version: 3.2 Severity: Normal | Resolution: Keywords: | Triage Stage: Accepted Has patch: 0 | Needs documentation: 0 Needs tests: 0 | Patch needs improvement: 0 Easy pickings: 0 | UI/UX: 0 --------------------------------------+------------------------------------
Comment (by Oguzhan Akan): I was able to reproduce the issue, but am not 100% sure if the suggested fix is correct. First let's see the following example: {{{ # ../tests/generic_relations_regress/models.py class CustomCharField(models.CharField): def get_prep_value(self, value): value = super().get_prep_value(value) return self.to_python(value) + "-pk" class Foo1(models.Model): id = models.CharField(primary_key=True, max_length=25) class Bar1(models.Model): content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = CustomCharField(max_length=25) content_object = GenericForeignKey() class Foo2(models.Model): id = models.CharField(primary_key=True, max_length=25) class Bar2(models.Model): content_type = models.ForeignKey(ContentType, models.CASCADE) object_id = models.CharField(max_length=25) content_object = GenericForeignKey() }}} with the test functions {{{ # ../tests/generic_relations_regress/tests.py # ..imports class GenericRelationTests(TestCase): def test_custom_prep_value_access_1(self): foo = Foo1.objects.create(pk="some-test") bar = Bar1.objects.create(content_object=foo) self.assertEqual( foo, Bar1.objects.prefetch_related("content_object").get(pk=1).content_object, ) # fails def test_custom_prep_value_access_2(self): foo = Foo2.objects.create(pk="some-test") bar = Bar2.objects.create(content_object=foo) self.assertEqual( foo, Bar2.objects.prefetch_related("content_object").get(pk=1).content_object, ) # passes }}} From the example above, the first test fails while the second passes. 1. In the first test, `Bar1`'s `object_id` is a `CustomCharField`, which has its `get_prep_value` function customized. 2. Then, the `content_object` is set to `None` as `GenericForeignKey.get_prefetch_queryset` function returns empty list for `ret_val`. This happens because the `get_all_objects_for_this_type` function ([https://github.com/django/django/blob/a7c73b944f51d6c92ec876fd7e0a171e7c01657d/django/contrib/contenttypes/fields.py#L200 #L200]) uses `fkeys` as the filter. The `fkeys` have the `prep`d values where the database stores the original strings as the primary key. 3. The suggested solution (running `get_prep_value` in `instance_attr` function) does not solve the problem as the `prep` function for Foo1 is different than the Bar1's. 4. In the second test, `Bar2`'s `object_id` is a default `CharField`, while Foo2 has a `CustomCharField` as its primary key. 5. The test passes as the `GenericForeignKey.get_prefetch_queryset` returns a non-empty return value. I believe one should not use a custom field for `object_id` referring a foreign key. Maybe a warning in docs would suffice? I can work more on this upon your suggestions. -- Ticket URL: <https://code.djangoproject.com/ticket/34819#comment:3> 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/0107018a84c76936-9023849a-e221-40f0-bc22-7af57871d451-000000%40eu-central-1.amazonses.com.