我有一个相当复杂的查询生成Django RawQuerySet
。此特定查询返回一些不属于RawQuerySet
所基于的模型的字段,因此我使用.annotate(field_name=models.Value('field_name'))
将其作为属性附加到RawQuerySet
中的各个记录。最重要的自定义字段实际上是uuid
,我用它来使用Django的{% url %}
功能组成URL。
这是问题所在:我没有在我的应用程序中使用标准的uuid
s,我正在使用SmallUUIDs(压缩的UUID)。这些存储在数据库中,因为本机uuidfield
s然后在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中的内容。
所以我正在考虑的是我的潜在解决方案,没有特别的顺序:
我最近的下一步是什么?
您目前的方法存在两个问题:
Value()
没有按照你的想法行事 - 你的注释实际上只是用值“my_uuid”注释每一行,因为这就是你传递给它的东西。它没有查找该名称的字段(要做到这一点,你需要使用F
表达式)。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)
(我只是为了说明而在循环中执行此操作 - 根据您需要的位置,您可以在模板标记或视图中执行此操作)。