与UUIDField的模型一起使用时,GenericForeignKey获取错误的id

时间:2018-05-25 10:16:32

标签: django uuid django-generic-relations

GenericForeignKeyUUIDField一起使用时,从通用对象的查询集中获取“真实模型”的查询集的推荐方法是什么?

以下是我正在测试的模型:

import uuid
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models

class Foo(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4)

class Generic(models.Model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.CharField(max_length=255)
    content_object = GenericForeignKey()

这是我到目前为止所尝试的:

>>> from django.db.models import Subquery
>>> from foo.models import Foo, Generic

>>> f = Foo.objects.create()
>>> g = Generic.objects.create(content_object=f)
>>> Foo.objects.filter(id__in=Subquery(Generic.objects.all().values('object_id')))
<QuerySet []>

>>> Generic.objects.get().object_id
'997eaf64-a115-4f48-b3ac-8cbcc21274a8'
>>> Foo.objects.get().pk
UUID('997eaf64-a115-4f48-b3ac-8cbcc21274a8')

我猜这与保存的UUID没有UUIDField的连字符有关。我无法将object_id变为UUIDField,因为我需要其他模型将整数和字符串作为主键。

我正在使用Django 1.11,但我也测试了同样存在问题的Django 2.0。

2 个答案:

答案 0 :(得分:2)

主要问题出在explicit type casts

所以,@ Alasdair的想法,你可以尝试:

foo_content_type = ContentType.objects.get_for_model(Foo)
gids = Generic.objects.filter(content_type=foo_content_type)
# create list of uuid strings
gids = list(gids.values_list('object_id', flat=True))
Foo.objects.filter(pk__in=gids)

其他解决方案:您可以将uuid字段添加到Generic模型中。例如:

class Generic(models.Model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.CharField(max_length=255)
    content_object = GenericForeignKey()
    uuid4 = models.UUIDField(blank=True, null=True)

    def save(self, *args, **kwargs):
        try:
            self.uuid4 = uuid.UUID(self.object_id)
        except Exception as e:
            pass
        super().save(*args, **kwargs)

和queryset将显示:

foo_content_type = ContentType.objects.get_for_model(Foo)
gids = Generic.objects.filter(content_type=foo_content_type).values('uuid4')
Foo.objects.filter(pk__in=gids)

答案 1 :(得分:0)

尝试删除oracle。您还希望按内容类型进行过滤。

Subquery()