Как сделать, чтобы оператор создания относился к "from_db_value" в пользовательских полях Django? - PullRequest
1 голос
/ 27 сентября 2019

Допустим, у меня есть настраиваемое поле, например:

class Temperature:
    pass

class TemperatureField(models.DecimalField):
    def from_db_value(self, value, expression, connection):
        if value is not None:
            return Temperature(value)
        return None

    def to_python(self, value):
        if isinstance(value, Temperature):
            return value
        if value is None:
            return value
        kelvin = super().to_python(value)
        return Temperature(kelvin)

    def get_prep_value(self, value):
        if isinstance(value, Temperature):
            value = value.kelvin
        return super().get_prep_value(value)

    def get_db_prep_save(self, value, connection):
        if isinstance(value, Temperature):
            return connection.ops.adapt_decimalfield_value(value.kelvin, self.max_digits, self.decimal_places)
        elif isinstance(value, (float, int)):
            return connection.ops.adapt_decimalfield_value(Decimal(value), self.max_digits, self.decimal_places)
        elif isinstance(value, (Decimal,)):
            return connection.ops.adapt_decimalfield_value(Decimal(value), self.max_digits, self.decimal_places)

class Test(models.Model):
    temp = TemperatureField(max_digits=10, decimal_places=2)

Следующее работает, как ожидалось, при загрузке данных из базы данных , например:

>>>t = Test.objects.first()
>>>t.temp
<extra_fields.fields.Temperature object at 0x10e733e50>
>>> type(t.temp)
<class 'extra_fields.fields.Temperature'>

Проблема в том, что логика для from_db_value не распространяется на create операторы:

>>>t = Test.objects.create(temp=1)
>>>t.temp
1
>>>type(t.temp)
<class 'int'>

Есть ли способ расширить эту логику до метода create, не переопределяя модельменеджер?IE, могу ли я сделать это в своем классе поля?

Я не думаю, что конкретные сведения о том, что делает класс Temperature, актуальны, но если вы хотите знать, см. Ответ на мой другой вопрос.

1 Ответ

1 голос
/ 28 сентября 2019

Это известная проблема .

В списке рассылки разработчиков Django есть ветка , в которой это обсуждается более подробно, и, по общему мнению, необходимо обновить документацию, чтобы предупредить об этом (этого еще не произошло)).

Решение состоит в том, чтобы либо обновить объект из базы данных:

t.refresh_from_db()

, либо принудительно очистить его:

t.full_clean()
...