Недавно нактнулся на интересную особенность Odoo, которая касается поля типа Selection
. Она заключается в том, что если в списке есть значение с ключом 0, то при выводе оно зануляется. Например, есть поле:
...
status = fields.Selection([(0, "Начало"), (1, "Конец")])
...
Так вот это поле при нахождении в таблице БД 0 в столбце status, в интерфейс выведет пустое значение, не строку “Начало”.
Такое поведение было для меня слегка неожиданным, но я подумал что оно связано с особенностью python и я полез смотерть исходники класса fields.Selection
.
Оказалось там есть 2 инетересных функции:
convert_to_read
- отвечает за отображение значения поля при выполнении у модели метода readconvert_to_column
- отвечает за преобразование значения в sql формат при вызове у модели методаwrite
.
Надо отметить что такие функции есть и у других типов полей не только Selection.
Код convert_to_read
:
def convert_to_read(self, value, record, use_name_get=True):
return False if value is None else value
В этой функции проблема в том, что при 0 значение value приходит None (так как значение 0 при чтении из БД интерпретируется в None из-за особенностей python), и поэтому возвращается False, а не значение 0.
Вторая проблема, по сути, аналогична и содежится в коде convert_to_column
:
def convert_to_column(self, value, record):
""" Convert ``value`` from the ``write`` format to the SQL format. """
if value is None or value is False:
return None
if isinstance(value, unicode):
return value.encode('utf8')
return str(value)
Как можно заметить тут проверяется значение на пустоту, и если его нет, то возвращается пустота и в БД идет значение NULL.
Если переопределить эти функции как показано ниже, то проблема c 0 будет решена:
class ZeroSelection(fields.Selection):
"""
Переопределение класса поля выбора, для корректной обработки значений показателей
смен активности.
"""
def convert_to_read(self, value, record, use_name_get=True):
"""
Переопределение метода для конвертации пустых значенй 0, вместо False.
Т. к. без этого некорретно обрабатываются типы и статусы активностей
"""
return 0 if value in [None, False] else value
def convert_to_column(self, value, record):
""" Переопределение метода для получения значение для SQL запроса на вставку, т.к.
по умолчанию 0 интепритируется как null, что в нашем случае не верно
"""
if isinstance(value, int):
return str(value)
return super(ZeroSelection, self).convert_to_column(value, record)