94 lines
3.2 KiB
Python
94 lines
3.2 KiB
Python
import pypinyin
|
|
|
|
from odoo import fields, models, api
|
|
from odoo.models import BaseModel
|
|
import re
|
|
|
|
_origin_search = BaseModel._search
|
|
_origin_read_group = BaseModel._read_group
|
|
|
|
|
|
|
|
class CharWithPinyin(fields.Char):
|
|
pass
|
|
|
|
# 把字段挂到 fields 命名空间
|
|
fields.CharWithPinyin = CharWithPinyin
|
|
|
|
|
|
_origin_setup_fields = BaseModel._setup_fields
|
|
|
|
def _my_setup_fields(self):
|
|
_origin_setup_fields(self)
|
|
# 把字段挂到 fields 命名空间
|
|
cls = self.env.registry[self._name]
|
|
for name in list(cls._fields):
|
|
field = self._fields[name]
|
|
# if isinstance(field, CharWithPinyin):
|
|
if type(field) == fields.CharWithPinyin:
|
|
new_field_name = f'{name}_pinyin'
|
|
compute_method_name = f'_compute_{new_field_name}'
|
|
if new_field_name not in cls._fields:
|
|
def _compute_func(self, fn=name, nfn=new_field_name):
|
|
for rec in self:
|
|
value = rec[fn] or ''
|
|
rec[nfn] = ''.join(pypinyin.lazy_pinyin(value))
|
|
|
|
setattr(cls, compute_method_name, api.depends(name)(_compute_func))
|
|
|
|
cls._add_field(
|
|
self,
|
|
new_field_name,
|
|
fields.Char(
|
|
compute=_compute_func,
|
|
store=True,
|
|
index=True,
|
|
string=f"{field.string or name}拼音",
|
|
)
|
|
)
|
|
|
|
BaseModel._setup_fields = _my_setup_fields
|
|
|
|
|
|
def _replace_char_with_pinyin_order(self, order):
|
|
"""
|
|
将排序字符串中属于 CharWithPinyin 的字段替换为对应 _pinyin 字段
|
|
"""
|
|
if not order:
|
|
return order
|
|
|
|
# 拆分多字段排序,例如 "name desc, create_date asc"
|
|
parts = [p.strip() for p in order.split(',')]
|
|
new_parts = []
|
|
for part in parts:
|
|
# 分离字段名和排序方向
|
|
m = re.match(r'([^\s]+)(?:\s+(asc|desc))?$', part, re.IGNORECASE)
|
|
if not m:
|
|
new_parts.append(part)
|
|
continue
|
|
field_name, direction = m.groups()
|
|
field = self._fields.get(field_name)
|
|
# if field and isinstance(field, fields.CharWithPinyin):
|
|
if field and type(field) == fields.CharWithPinyin:
|
|
# 替换成 _pinyin 字段
|
|
field_name = f"{field_name}_pinyin"
|
|
if direction:
|
|
new_parts.append(f"{field_name} {direction}")
|
|
else:
|
|
new_parts.append(field_name)
|
|
return ', '.join(new_parts)
|
|
|
|
|
|
# 重写 _search
|
|
def _my_search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
|
|
order = _replace_char_with_pinyin_order(self, order)
|
|
return _origin_search(self, domain, offset=offset, limit=limit, order=order, access_rights_uid=access_rights_uid)
|
|
|
|
# 重写 _read_group
|
|
def _my_read_group(self, domain, groupby=(), aggregates=(), having=(), offset=0, limit=None, order=None):
|
|
order = _replace_char_with_pinyin_order(self, order)
|
|
return _origin_read_group(self, domain, groupby=groupby, aggregates=aggregates, having=having, offset=offset, limit=limit, order=order)
|
|
|
|
# Patch BaseModel
|
|
BaseModel._search = _my_search
|
|
BaseModel._read_group = _my_read_group |