将django RawQueryset中字段的值转换为不同的django字段类型

问题描述 投票:3回答:1

我有一个相当复杂的查询生成Django RawQuerySet。此特定查询返回一些不属于RawQuerySet所基于的模型的字段,因此我使用.annotate(field_name=models.Value('field_name'))将其作为属性附加到RawQuerySet中的各个记录。最重要的自定义字段实际上是uuid,我用它来使用Django的{% url %}功能组成URL。

这是问题所在:我没有在我的应用程序中使用标准的uuids,我正在使用SmallUUIDs(压缩的UUID)。这些存储在数据库中,因为本机uuidfields然后在python中转换为更短的字符串。所以我需要以某种方式将uuid作为RawQuerySet的一部分返回到SmallUUID,以便在模板中使用以生成URL。

我的代码看起来有点像这样:

query = "SELECT othertable.uuid_field as my_uuid FROM myapp_mymodel
         JOIN othertable o ON myapp_mymodel.x = othertable.x"

MyModel.objects.annotate(
    my_uuid=models.Value('my_uuid'),
).raw(query)

现在这里有一个逻辑解决方案,models.Value有一个名为output_field的可选kwarg,使代码看起来像这样:

MyModel.objects.annotate(
    my_uuid=models.Value('my_uuid', output_field=SmallUUIDField()),
).raw(query)

但它不起作用!该kwarg被完全忽略,属性的类型基于从数据库返回的类型,而不是output_field中的类型。在我的情况下,我得到一个uuid输出,因为Postgres返回一个UUID类型,但如果我要将查询更改为SELECT cast othertable.uuid_field as text) as my_uuid,我将获得字符串格式的属性。似乎Django(至少版本1.11.12)实际上并不关心这个实例中那个kwarg中的内容。

所以我正在考虑的是我的潜在解决方案,没有特别的顺序:

  1. 以某种方式更改查询格式的方式(在Django或SQL中)
  2. 在传递给视图之前,以某种方式更改生成的RawQuerySet
  3. 更改模板内的内容以将UUID转换为smalluuid,以便在URL反向过程中使用。

我最近的下一步是什么?

django django-models django-queryset django-postgresql
1个回答
1
投票

您目前的方法存在两个问题:

  1. Value()没有按照你的想法行事 - 你的注释实际上只是用值“my_uuid”注释每一行,因为这就是你传递给它的东西。它没有查找该名称的字段(要做到这一点,你需要使用F表达式)。
  2. 无论如何,上面的第1点无关紧要,因为只要你使用raw(),那么注释就会被忽略 - 这就是为什么你看不到来自它的效果。

底线是试图注释RawQuerySet并不容易。它接受了一个translations参数,但我想不出一种方法可以使用你正在使用的连接类型。

我能想到的下一个最佳建议是,只需在需要时手动将字段转换为SmallUUID对象 - 如下所示:

from smalluuid import SmallUUID

objects = MyModel.objects.raw(query)

for o in objects:
    # Take the hex string obtained from the database and convert it to a SmallUUID object.
    # If your database has a built-in UUID type you will need to do 
    # SmallUUID(small=o.my_uuid) instead.
    my_uuid = SmallUUID(hex=o.my_uuid)

(我只是为了说明而在循环中执行此操作 - 根据您需要的位置,您可以在模板标记或视图中执行此操作)。

© www.soinside.com 2019 - 2024. All rights reserved.