Могу ли я расширить поля модели Django без создания смешанных типов?

Я подклассифицировал встроенные модели Field для уменьшения повторений в похожих колонках. Это вызывает исключения в тестах на Django 3.2 (но, что интересно, работает в неактуальной, не поддерживаемой сейчас версии 2.2)

django.core.exceptions.FieldError: Выражение содержит смешанные типы: DecimalField, DecimalFWB. Вы должны установить output_field.

.
class DecimalFWB(DecimalField):
    def validators(self):
        return super().validators() + [MinValueValidator(0.1), ]
    ...

class Repro(Model):
   frac = DecimalFWB(max_digits=4, decimal_places=4, default=Decimal("0.2"))
   ...

# same internal type
assert DecimalFWB().get_internal_type() == DecimalField().get_internal_type()

# 3.2: django.core.exceptions.FieldError
# 2.2: works
Repro.objects.annotate(dec_annotation = Decimal(1) - F("frac"))

# 3.2: works
# 2.2: works
Repro.objects.annotate(dec_annotation = -F("frac") + Decimal(1))

Я нашел эту запись в Django 3.2 release notes, которая может объяснить изменение поведения по сравнению с предыдущей версией:

[...] разрешение поля output_field для функций базы данных и комбинированных выражений теперь может привести к сбою при смешанных типах при использовании Value(). В таких случаях необходимо явно задавать поле вывода.

Это предложение не решает мою проблему. Если бы я раздул все аннотации с помощью ExpressionWrapper/output_field=, я мог бы с тем же успехом раздуть определение модели и вообще не использовать подкласс.

Я пытаюсь эмулировать внутренний тип . Я хочу, чтобы объединенное выходное_поле DecimalField и DecimalFWB было DecimalField - независимо от порядка супер/подкласса. Как мне выразить, что здесь не происходит смешивания?

Автоматический выбор общего поля в качестве вывода был исправлен в Bug #33397, выпущенном в Django 4.1 (но не бэкпортированном). Однако это изменение сопровождается предупреждением (выделение мое):

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

Это предположение в основном плохая идея, но есть довольно много кода (особенно сторонних подклассов Func), которые зависят от него, нам понадобится чтобы исправить это.

Имеется в виду, что это может снова измениться в будущем выпуске, но по крайней мере тогда намеренно и надежно вызывать DeprecationWarning по запросу.

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