Reputation: 1087
I need to annotate something that has to be named 'id' that is the same as the primary key of the table 'id'. The final output should be an array of dictionaries. I know that I can annotate with another name like 'id_for_tree' and then after using values()
to make the dictionaries and change the key in a loop. Something like:
item_list = MyTable.objects.annotate(id_for_tree=Concat(F('id'), F('Code'), output_field=CharField())).values('Name', 'id_for_tree')
for any_item in item_list:
any_item['id'] = any_item.pop('id_for_tree')
It's clear that this solution does not have a good performance. How can I get rid of the
"The annotation 'id' conflicts with a field on the model"
exception by discarding the previous 'id'
and annotate a new 'id'
?
Upvotes: 3
Views: 8609
Reputation: 1747
"something that has to be named 'id'"
Why?
Anyway, that aside, have you tried simply moving the call to values
ahead of the call to annotate
?
i.e.
item_list = MyTable.objects.values('Name').annotate(id=Concat(F('id'), F('Code'), output_field=CharField()))
This is predicated on the Name
field also being unique.
EDIT: If the Name
field is not unique, then you can do it with an extra call to values
and annotate
.
i.e.
item_list = MyTable.objects.values(
'Name', 'id'
).annotate(
id_dummy=Concat(F('id'), F('Code'), output_field=CharField())
).values(
'id_dummy',
'Name'
).annotate(
id=F('id_dummy')
)
EDIT from question owner: Finally, I used this code to avoid unintentionally group_by:
item_list = MyTable.objects.annotate(
OriginalId=F('id')
).values(
'Name',
'OriginalId'
).annotate(
id=Concat(F('id'), F('Code'), output_field=CharField()
))
Upvotes: 7