如何在 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 方法可以做到这一点?
你至少要考虑两件事:
使用search
(或search_count
)从数据库中获取记录。您可以使用参数 order
来告诉 Odoo 记录应该由数据库直接排序的顺序。因此,例如使用 self.env['fruits'].search([], order="LOWER(name)")
以“真实”字母顺序在“名称”列上获取所有水果。
要考虑的第二部分是对 python 中的记录进行排序。但是可以在那里使用相同的主体。排序时只是小写或大写。
第三方可以是直接查询,但在此上下文中使用它们与从第 1 点开始“搜索”一样。因为 order
参数将在 Odoo 构建的查询中设置无论如何在 search
结束时。
当 Odoo 搜索记录时,它会尝试根据 order_spec
构造一个合适的 ORDER BY clause
,它必须是一个逗号分隔的有效字段名称列表,后面可以选择跟一个 ASC
或 DESC
方向。
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,)
无需重新定义顺序。
我的用例是按名称列出树或看板视图中的记录,但它应该不区分大小写。 当前状态 例如。我有四个记录
Apple
Orange
apple
Banana
默认顺序为:
Apple
Banana
Orange
apple
预期的顺序是:
Apple
apple
Banana
Orange
如何实现?是否有任何 ORM 方法可以做到这一点?
你至少要考虑两件事:
使用
search
(或search_count
)从数据库中获取记录。您可以使用参数order
来告诉 Odoo 记录应该由数据库直接排序的顺序。因此,例如使用self.env['fruits'].search([], order="LOWER(name)")
以“真实”字母顺序在“名称”列上获取所有水果。要考虑的第二部分是对 python 中的记录进行排序。但是可以在那里使用相同的主体。排序时只是小写或大写。
第三方可以是直接查询,但在此上下文中使用它们与从第 1 点开始“搜索”一样。因为 order
参数将在 Odoo 构建的查询中设置无论如何在 search
结束时。
当 Odoo 搜索记录时,它会尝试根据 order_spec
构造一个合适的 ORDER BY clause
,它必须是一个逗号分隔的有效字段名称列表,后面可以选择跟一个 ASC
或 DESC
方向。
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,)
无需重新定义顺序。