将 django RawQueryset 中的字段值转换为不同的 django 字段类型
Convert the value of a field in a django RawQueryset to a different django field type
我有一个生成 Django RawQuerySet
的相当复杂的查询。这个特定的查询 returns 一些不属于 RawQuerySet
所基于的模型的字段,所以我使用 .annotate(field_name=models.Value('field_name'))
将其作为属性附加到RawQuerySet
。最重要的自定义字段实际上是一个 uuid
,我用它来使用 Django 的 {% url %}
功能编写 URLs。
问题是:我没有在我的应用程序中使用标准 uuid
,我使用的是 SmallUUIDs(压缩的 UUID。)它们作为原生 [=19] 存储在数据库中=]s 然后在 python 中转换为较短的字符串。所以我需要以某种方式将作为 RawQuerySet
的一部分返回的 uuid
转换为 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
有一个可选的 kwarg 称为 output_field
,使代码看起来像这样:
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 中的内容。
下面是我认为的潜在解决方案,排名不分先后:
- 以某种方式更改查询的格式化方式(在 Django 或 SQL 中)
- 在传递给视图之前以某种方式更改生成的 RawQuerySet
- 更改模板中的某些内容以将 UUID 转换为 smalluuid,以便在 URL 反向过程中使用。
我最好的后续步骤是什么?
您当前方法的几个问题:
Value()
并没有按照您的想法行事 - 您的注释实际上只是用值 "my_uuid" 注释每一行,因为那是您传递给它的内容.它不是在查找该名称的字段(为此您需要使用 F
表达式)。
上面的第 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)
(我循环执行此操作只是为了说明 - 根据您需要的位置,您可以在模板标签或视图中执行此操作)。
我有一个生成 Django RawQuerySet
的相当复杂的查询。这个特定的查询 returns 一些不属于 RawQuerySet
所基于的模型的字段,所以我使用 .annotate(field_name=models.Value('field_name'))
将其作为属性附加到RawQuerySet
。最重要的自定义字段实际上是一个 uuid
,我用它来使用 Django 的 {% url %}
功能编写 URLs。
问题是:我没有在我的应用程序中使用标准 uuid
,我使用的是 SmallUUIDs(压缩的 UUID。)它们作为原生 [=19] 存储在数据库中=]s 然后在 python 中转换为较短的字符串。所以我需要以某种方式将作为 RawQuerySet
的一部分返回的 uuid
转换为 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
有一个可选的 kwarg 称为 output_field
,使代码看起来像这样:
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 中的内容。
下面是我认为的潜在解决方案,排名不分先后:
- 以某种方式更改查询的格式化方式(在 Django 或 SQL 中)
- 在传递给视图之前以某种方式更改生成的 RawQuerySet
- 更改模板中的某些内容以将 UUID 转换为 smalluuid,以便在 URL 反向过程中使用。
我最好的后续步骤是什么?
您当前方法的几个问题:
Value()
并没有按照您的想法行事 - 您的注释实际上只是用值 "my_uuid" 注释每一行,因为那是您传递给它的内容.它不是在查找该名称的字段(为此您需要使用F
表达式)。上面的第 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)
(我循环执行此操作只是为了说明 - 根据您需要的位置,您可以在模板标签或视图中执行此操作)。