Django динамическое приведение полей при аннотировании
Допустим, я хочу сохранить эти данные в db:
{
"fields": [
{
"field_type": "number",
"name": "field_1",
"value": 8223,
},
{
"field_type": "string",
"name": "field_2",
"value": "demo"
},
{
"field_type": "bool",
"name": "field_3",
"value": true
}
],
"blockchain_id": 47,
"name": "event",
"block_number": 3916102,
}
Здесь value является динамическим, основываясь на значении field_type. Вот мои модели:
class Event(models.Model):
blockchain_id = models.IntegerField()
name = models.CharField(max_length=100)
block_number = models.IntegerField()
fields = models.ManyToManyField(EventField)
class EventField(models.Model):
TYPE_CHOICES = (
('number', 'Number'),
('string', 'String'),
('bool', 'Boolean'),
)
field_type = models.CharField(max_length=6, choices=TYPE_CHOICES)
name = models.CharField(max_length=100)
value = models.CharField(max_length=100)
Я сохраняю динамические value как Character (вы можете предложить что-то лучшее). Затем, когда я извлекаю эти значения, я хочу отбрасывать их на основе значения field_type. Пока что вот мой запрос:
Event.objects.filter(id=_id).annotate(fields_value=Case(
When(fields__field_type='number', then=Cast('fields__value', output_field=models.IntegerField())),
When(fields__field_type='string', then=Cast('fields__value', output_field=models.CharField())),
When(fields__field_type='bool', then=Cast('fields__value', output_field=models.BooleanField())),
output_field=Case(When(fields__field_type='number', then=models.IntegerField()))))
Теперь я получаю это сообщение об ошибке Cannot resolve expression type, unknown output_field .Возможно, я что-то упускаю. Как я могу вернуть значение, используя приведение на основе типа_поля?
Вы не можете работать с таким динамическим литьем: для SQL каждый столбец имеет определенный тип и все записи используют один и тот же тип для этого столбца.
Вам нужно будет сделать это на уровне Django/Python, например, с помощью:
class EventField(models.Model):
TYPE_CHOICES = (
('number', 'Number'),
('string', 'String'),
('bool', 'Boolean'),
)
field_type = models.CharField(max_length=6, choices=TYPE_CHOICES)
name = models.CharField(max_length=100)
value = models.CharField(max_length=100)
@property
def typed_value(self):
if self.field_type == 'number':
return int(self.value)
if self.field_type == 'string':
return self.value
if self.field_type == 'bool':
return self.value.casefold() == 'true'
raise ValueError('Invalid field type.')
Затем вы можете проверить значение с помощью my_event_field.typed_value.