我有一个相当复杂的查询,它生成一个Django RawQuerySet
。此特定查询返回的某些字段不属于RawQuerySet
所基于的模型的一部分,因此我使用.annotate(field_name=models.Value('field_name'))
将其作为属性附加到RawQuerySet
。最重要的自定义字段实际上是uuid
,我用它来使用Django的{% url %}
功能来构建网址。
问题在于:我没有在我的应用程序中使用标准uuid
,我使用SmallUUIDs(压缩的UUID)。这些都存储在数据库作为本机uuidfield
然后在python中转换为更短的字符串。所以我需要以某种方式将uuid
作为RawQuerySet
的一部分返回到SmallUUID
,以便在模板中使用以生成网址。
我的代码看起来有点像这样:
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中的内容。
所以,我在想的是我的潜在解决方案,没有特别的顺序:
我最近的下一步是什么?
答案 0 :(得分:1)
您目前的方法存在两个问题:
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)
(我在循环中这样做只是为了说明 - 根据你需要的地方,你可以在模板标签或视图中做到这一点。)