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

Reply via email to