Сообщение об ошибке django "can't adapt type '__proxy__'"

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}
]

Но поле gender является полем выбора, так что, вывод, который я хочу, выглядит так:

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

Я создал следующий класс, изучив ответ, данный @bachkoi32 Отображение имени поля выбора в Django при использовании annotate

Для вывода я использую этот класс:

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: can't adapt type '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())
Вернуться на верх