#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 [email protected].
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