【问题标题】:How to get record in true alphabetically ( case insensitive ) sort order in odoo?如何在odoo中以真正的字母顺序(不区分大小写)排序顺序获取记录?
【发布时间】:2021-08-25 05:40:12
【问题描述】:

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

Apple
Orange
apple
Banana

默认排序为:

Apple
Banana
Orange
apple

预期的顺序是:

Apple
apple
Banana
Orange

如何做到这一点?有什么 ORM 方法可以做到这一点吗?

【问题讨论】:

    标签: python postgresql orm odoo odoo-14


    【解决方案1】:

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

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

    您可以覆盖_generate_order_by_inner 函数,以便可以直接在char 字段的_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,)
    

    无需重新定义顺序。

    【讨论】:

      【解决方案2】:

      你至少要考虑两件事:

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

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

      第三部分可以是直接查询,但在这种情况下使用它们就像从第 1 点开始执行“搜索”一样。因为 order 参数将在 Odoo 正在构建的查询中设置在末尾search 反正。

      【讨论】:

      • self.env['fruits'].search([], order="LOWER(name)") 真的有效吗?我收到了'Invalid "order" specified. A valid "order" specification is a comma-separated list of valid field names (optionally followed by asc/desc for the direction)',尽管是在 Odoo 11 中。
      • 哦,Odoo 真的会检查这个参数吗……好吧,这很糟糕。在 Odoo 14 上测试过,它不工作......好吧,我将更改或删除我的答案。
      • 您可以使用返回name.lower() 的计算字段吗?
      • 是的,必须保存。
      • 其实str.casefold会比.lower好。
      猜你喜欢
      • 2011-08-14
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      • 2020-03-20
      • 2018-12-14
      • 1970-01-01
      • 2012-09-20
      • 2023-03-27
      相关资源
      最近更新 更多