Сообщение об ошибке 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())