Могу ли я расширить поля модели 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 по запросу.