使用注释时 Django 中选择字段的显示名称

bac*_*i32 7 python django django-models django-forms django-queryset

我试图在使用注释时获取选项的显示名称,但我一直无法弄清楚。我有以下查询:

Survey.objects.values('what').annotate(count=Count('why')).order_by()
Run Code Online (Sandbox Code Playgroud)

结果是:

[{'count': 34, 'what': u'a'}, 
{'count': 39, 'what': u'c'}, 
{'count': 40, 'wat': u'p'}]
Run Code Online (Sandbox Code Playgroud)

但我想要显示选择字段的名称而不是键的内容:

[{'count': 34, 'what': u'appreciative'}, 
{'count': 39, 'what': u'creative'}, 
{'count': 40, 'wat': u'promising'}]
Run Code Online (Sandbox Code Playgroud)

我尝试了 get_what_display (如文档和有关此主题的其他 stackoverflow 答案中提到的),但 django 抛出错误。即以下似乎不起作用

Survey.objects.values('get_what_display').annotate(count=Count('why')).order_by()
Run Code Online (Sandbox Code Playgroud)

bdo*_*leu 8

要在不迭代查询集的情况下完成此操作,您可以使用条件表达式来注释显示属性。带注释的属性可在.values().

from django.db.models import Case, CharField, Value, When

choices = dict(Survey._meta.get_field('what')[0].flatchoices)
whens = [When(what=k, then=Value(v)) for k, v in choices.items()]
survey_counts = (
    Survey.objects
    .annotate(get_what_display=Case(*whens, output_field=CharField()))
    .values('get_what_display')
    .annotate(count=Count('why'))
    .order_by()
)
Run Code Online (Sandbox Code Playgroud)


And*_*rra 6

根据 @bdoubleu 的回答,我编写了以下通用条件表达式:

# myapp/utils.py
from django.db.models import Case, CharField, Value, When

class WithChoices(Case):
    def __init__(self, model, field, condition=None, then=None, **lookups):
        choices = dict(model._meta.get_field(field).flatchoices)
        whens = [When(**{field: k, 'then': Value(v)}) for k, v in choices.items()]
        return super().__init__(*whens, output_field=CharField())

# example usage
from myapp.utils import WithChoices
from myapp.models import MyModel
MyModel.objects.annotate(what_with_choices=WithChoices(MyModel, 'what')).values('what_with_choices')
Run Code Online (Sandbox Code Playgroud)

可能有一种更简洁的构建方法,不需要将参数传递model给 WithChoices,但是,嘿,这可行。


ozg*_*gur 4

正如前面所说,get_FOO_display是一个实例方法,而不是您可以在.values(). 因此,我会使用 Pythonic 方式来完成你想做的事情:

from django.utils.encoding import force_text

survey_counts = Survey.objects.values('what').annotate(count=Count('why')).order_by()

choices = dict(Survey._meta.get_field_by_name('what')[0].flatchoices)
for entry in survey_counts:
    entry['what'] = force_text(choices[entry['what']], strings_only=True)
Run Code Online (Sandbox Code Playgroud)

  • 只是 Django 1.10 的小更新:`choices = dict(Survey._meta.get_field('what').flatchoices)` (2认同)