- create model with UUID as primary key
{{{
class Foo(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4,
editable=False)
...
}}}
- create another model with GFK to model Foo
{{{
class Bar(models.Model):
foo_content_type = models.ForeignKey(
ContentType, related_name='actor',
on_delete=models.CASCADE, db_index=True
)
foo_object_id = models.CharField(max_length=255, db_index=True)
foo = GenericForeignKey('foo_content_type', 'foo_object_id')
...
}}}
- and try to get queryset with prefetch related (django orm engine return
None for attribute **foo**):
{{{
Bar.objects.all().prefetch_related('foo')
}}}
Thanks a lot for your attention! Also i wanna point out some related bug
report from third party library in which previously i faced with that
issue, maybe it would useful – [https://github.com/justquick/django-
activity-stream/issues/245]
--
Ticket URL: <https://code.djangoproject.com/ticket/30343>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* status: new => closed
* version: 2.2 => master
* resolution: => wontfix
Comment:
Thanks for the report, however `GenericForeignKey` doesn't support
`prefetch_related()`, from the same reason it doesn't not support also
`filter()`, `exclude()`, etc. Please see
[https://docs.djangoproject.com/en/2.2/ref/contrib/contenttypes/#generic-
relations documentation]:
{{{
Due to the way GenericForeignKey is implemented, you cannot use such
fields directly with filters (filter() and exclude(), for example) via the
database API. Because a GenericForeignKey isn’t a normal field object,
these examples will not work:
...
}}}
Provided example works as expected with UUID PK, e.g.:
{{{
>>> for bar in Bar.objects.all():
... print(bar, bar.foo)
Bar object (4) Foo object (e6bdfd5e-51a8-49c7-9a7a-998452fad6aa)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30343#comment:1>
* status: closed => new
* resolution: wontfix =>
* stage: Unreviewed => Accepted
Comment:
Sorry for previous comment.
This should work. Currently it works when `foo_object_id` is an
`UUIDField` but doesn't work when it is a `CharField`.
--
Ticket URL: <https://code.djangoproject.com/ticket/30343#comment:2>
* Attachment "30343-test.diff" added.
Comment (by felixxm):
IMO, adding `get_prep_value()` to the `UUIDField` should fix this issue
🤔:
{{{
diff --git a/django/db/models/fields/__init__.py
b/django/db/models/fields/__init__.py
index 2307dcae25..0a7a6b9736 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -2335,6 +2335,12 @@ class UUIDField(Field):
return value
return value.hex
+ def get_prep_value(self, value):
+ value = super().get_prep_value(value)
+ if value is None:
+ return None
+ return self.to_python(value)
+
def to_python(self, value):
if value is not None and not isinstance(value, uuid.UUID):
input_form = 'int' if isinstance(value, int) else 'hex'
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30343#comment:3>
Comment (by Simon Charette):
Yeah that seems like the correct approach. I was about to suggest
{{{#!diff
diff --git a/django/contrib/contenttypes/fields.py
b/django/contrib/contenttypes/fields.py
index ed98ecb48c..6098b71a39 100644
--- a/django/contrib/contenttypes/fields.py
+++ b/django/contrib/contenttypes/fields.py
@@ -202,7 +202,7 @@ class GenericForeignKey(FieldCacheMixin):
else:
model = self.get_content_type(id=ct_id,
using=obj._state.db).model_class()
- return (model._meta.pk.get_prep_value(getattr(obj,
self.fk_field)),
+ return (model._meta.pk.to_python(getattr(obj,
self.fk_field)),
model)
}}}
But it looks like this is really just an issue with `UUIDField`.
--
Ticket URL: <https://code.djangoproject.com/ticket/30343#comment:4>
* owner: nobody => felixxm
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/30343#comment:5>
* has_patch: 0 => 1
Comment:
[https://github.com/django/django/pull/11211 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/30343#comment:6>
Comment (by Timur):
Replying to [comment:6 felixxm]: Thanks for your work!
> [https://github.com/django/django/pull/11211 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/30343#comment:7>
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/30343#comment:8>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"1afbc96a75bd1765a56054f57ea2d4b238af3f4d" 1afbc96]:
{{{
#!CommitTicketReference repository=""
revision="1afbc96a75bd1765a56054f57ea2d4b238af3f4d"
Fixed #30343 -- Fixed prefetch_related() for GenericForeignKey when PK of
related field is UUIDField.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30343#comment:9>