如何在 odoo 中以真正的字母顺序(不区分大小写)排序顺序获取记录?

How to get record in true alphabetically ( case insensitive ) sort order in odoo?

我的用例是按名称列出树或看板视图中的记录,但它应该不区分大小写。 当前状态 例如。我有四个记录

Apple
Orange
apple
Banana

默认顺序为:

Apple
Banana
Orange
apple

预期的顺序是:

Apple
apple
Banana
Orange

如何实现?是否有任何 ORM 方法可以做到这一点?

你至少要考虑两件事:

  1. 使用search(或search_count)从数据库中获取记录。您可以使用参数 order 来告诉 Odoo 记录应该由数据库直接排序的顺序。因此,例如使用 self.env['fruits'].search([], order="LOWER(name)") 以“真实”字母顺序在“名称”列上获取所有水果。

  2. 要考虑的第二部分是对 python 中的记录进行排序。但是可以在那里使用相同的主体。排序时只是小写或大写。

第三方可以是直接查询,但在此上下文中使用它们与从第 1 点开始“搜索”一样。因为 order 参数将在 Odoo 构建的查询中设置无论如何在 search 结束时。

当 Odoo 搜索记录时,它会尝试根据 order_spec 构造一个合适的 ORDER BY clause,它必须是一个逗号分隔的有效字段名称列表,后面可以选择跟一个 ASCDESC 方向。

order by 子句是根据 _order 属性计算的,可以被搜索函数中的 order 参数覆盖。

您可以重写 _generate_order_by_inner 函数,以便直接在 _order 属性 (field_name:function) 中为字符字段传递 SQL 查询中使用的函数名称。

示例:

class Fruits(models.Model):
    _name = 'fruit.fruit'
    _order = 'name:lower'

    name = fields.Char()

    @api.model
    def _generate_order_by_inner(self, alias, order_spec, query, reverse_direction=False, seen=None):
        if seen is None:
            seen = set()
        self._check_qorder(order_spec)

        order_by_elements = []
        for order_part in order_spec.split(','):
            order_split = order_part.strip().split(' ')
            order_field = order_split[0].strip()
            order_direction = order_split[1].strip().upper() if len(order_split) == 2 else ''
            if reverse_direction:
                order_direction = 'ASC' if order_direction == 'DESC' else 'DESC'
            do_reverse = order_direction == 'DESC'
            # ------------------------------------------------------------------
            func_split = order_field.strip().split(':')
            order_field = func_split[0].strip()
            func = func_split[1].strip().upper() if len(func_split) == 2 else ''
            # ------------------------------------------------------------------
            field = self._fields.get(order_field)
            if not field:
                raise ValueError("Invalid field %r on model %r" % (order_field, self._name))
            
            if order_field == 'id':
                order_by_elements.append('"%s"."%s" %s' % (alias, order_field, order_direction))
            else:
                if field.inherited:
                    field = field.base_field
                if field.store and field.type == 'many2one':
                    key = (field.model_name, field.comodel_name, order_field)
                    if key not in seen:
                        seen.add(key)
                        order_by_elements += self._generate_m2o_order_by(alias, order_field, query, do_reverse, seen)
                elif field.store and field.column_type:
                    qualifield_name = self._inherits_join_calc(alias, order_field, query)
                    if field.type == 'boolean':
                        qualifield_name = "COALESCE(%s, false)" % qualifield_name
                    # ------------------------------------------------------
                    if func and field.type == 'char':
                        qualifield_name = "%s(%s)" % (func, qualifield_name)
                    # ------------------------------------------------------
                    order_by_elements.append("%s %s" % (qualifield_name, order_direction))
                else:
                    _logger.warning("Model %r cannot be sorted on field %r (not a column)", self._name, order_field)
                    continue  # ignore non-readable or "non-joinable" fields

        return order_by_elements

您还可以修补 models.BaseModel._generate_order_by_inner 以对任何字符字段使用相同的逻辑。

示例:

@api.model
def _generate_order_by_inner(self, alias, order_spec, query, reverse_direction=False, seen=None):
    ...

models.BaseModel._generate_order_by_inner = _generate_order_by_inner

要覆盖任何视图中的排序顺序,您只需包括:

if field.type == 'char':
    qualifield_name = "lower(%s)" % (qualifield_name,)

无需重新定义顺序。