django "can't adapt type '__proxy__'" 错误信息

django "can't adapt type '__proxy__'" error message

class GenderTypeEnum:
    FEMALE = 1
    MALE = 2
    UNKNOWN = 3
    
    types = (
        (FEMALE, _("Female")),
        (MALE, _("Male")),
        (UNKNOWN, _("Unknown"))
    )

class PersonModel(models.Model):
    identity = models.CharField(max_length=50, unique=True)
    name = models.CharField(max_length=75)
    last_name = models.CharField(max_length=75)
    gender = models.PositiveIntegerField(choices=GenderTypeEnum.types)
    
class StaffModel(models.Model):
    person = models.ForeignKey('PersonModel', on_delete=models.CASCADE, related_name='staffs')
    registration_number = models.CharField(max_length=50, unique=True)
    start_date = models.DateField()
    finish_date = models.DateField(null=True, blank=True)

我正在使用以下查询来列出员工的性别统计信息

StaffModel.objects.values("person__gender").annotate(count=Count("person__gender"))

输出:

[
{"person__gender":1, "count":1}, 
{"person_gender":2, "count":5}
]

但是性别字段是一个选择字段,所以我想要的输出是这样的:

[
    {"person__gender":1, "gender_exp":"Male", "count":1}, 
    {"person_gender":2, "gender_exp":"Female", "count":5}
]

我通过查看给@bachkoi32 Display name of a choice field in Django while using annotate

的答案创建了以下 class

为了输出,我用这个class:

class WithChoices(Case):
    def __init__(self, model, field, condition=None, then=None, **lookups):
        fields = field.split('__')
        for f in fields:
            model = model._meta.get_field(f)

            if model.related_model:
                model = model.related_model

        choices = dict(model.flatchoices)
        whens = [When(**{field: k, 'then': Value(v)}) for k, v in choices.items()]
        return super().__init__(*whens, output_field=CharField())

我更改了我的查询:

qs = StaffModel.objects.values("person__gender").annotate(gender_exp=WithChoices(StaffModel, 'person__gender'), count=Count("person__gender")).values("person__gender","gender_exp","count")

当我想打印查询结果时,它引发了错误; django.db.utils.ProgrammingError: 无法适配类型 'proxy'

qs = StaffModel.objects.values("person__gender").annotate(gender_exp=WithChoices(StaffModel, 'person__gender'), count=Count("person__gender")).values("person__gender","gender_exp","count")
print(qs)

# raise error;
# django.db.utils.ProgrammingError: can't adapt type '__proxy__'

您选择的标签是惰性翻译,这些不能作为值传递给查询,需要使用 force_str

将它们转换为字符串
from django.utils.encoding import force_str


class WithChoices(Case):
    def __init__(self, model, field, condition=None, then=None, **lookups):
        fields = field.split('__')
        for f in fields:
            model = model._meta.get_field(f)

            if model.related_model:
                model = model.related_model

        choices = dict(model.flatchoices)
        whens = [When(**{field: k, 'then': Value(force_str(v))}) for k, v in choices.items()]
        return super().__init__(*whens, output_field=CharField())