Обработка значения 0 в поле выбора в Odoo

Недавно нактнулся на интересную особенность Odoo, которая касается поля типа Selection. Она заключается в том, что если в списке есть значение с ключом 0, то при выводе оно зануляется. Например, есть поле:

...

status = fields.Selection([(0, "Начало"), (1, "Конец")])

...

Так вот это поле при нахождении в таблице БД 0 в столбце status, в интерфейс выведет пустое значение, не строку “Начало”.

Такое поведение было для меня слегка неожиданным, но я подумал что оно связано с особенностью python и я полез смотерть исходники класса fields.Selection.

Оказалось там есть 2 инетересных функции:

  • convert_to_read - отвечает за отображение значения поля при выполнении у модели метода read
  • convert_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)
 
comments powered by Disqus