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.

Вернуться на верх