Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
631 views
in Technique[技术] by (71.8m points)

python - Combining Django F, Value and a dict to annotate a queryset

I have a scenario where I want to annotate a queryset with externally prepared data in a dict. I want to do something like the following:

value_dict = {"model1": 123.4, "model2": 567.8}
qs = ModelClass.objects.annotate(
    value=Value(value_dict.get(F('model__code'), 0))
)

The results currently show all as 0 as the F() doesn't seem to be the best way to look up the dict seeing as it doesn't return a string and it is resolved further down the track.

Your help and suggestions would be much appreciated

I'm currently on Python 3.6 and Django 1.11

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The closest I've come so far is to loop through the dict and union a whole bunch of filtered query sets based on the dict keys. Like so:

value_dict = {"model1": 123.4, "model2": 567.8}
array_of_qs = []
for k, v in value_dict.items():
    array_of_qs.append(
        ModelClass.objects.filter(model__code=k).annotate(value=Value(v))
    )
qs = array_of_qs[0].union(*array_of_qs[1:])

The qs will then have the result that I want, which is the values of the dict based on the keys of the dict annotated to each instance.

The beauty of this is that there is only one call to the db which is when I decide to use qs, other than that this whole process doesn't touch the DB from what I understand.

Not sure there is a better way yet but will wait to see if there are other responses before accepting this one.

NEW IMPROVED WORKING METHOD BELOW

Unfortunately the above doesn't work with values_list or values as of this current version 1.11 of Django due to this issue: https://code.djangoproject.com/ticket/28900

I devised a cleaner way below:

value_dict = {"model1": 123.4, "model2": 567.8}
whens = [
    When(model__code=k, then=v) for k, v in value_dict.items()
]
qs = ModelClass.objects.all().annotate(
    value=Case(
        *whens,
        default=0,
        output_field=DecimalField()
    )
)

Hope it helps someone


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...