Files
gzth/yuthon_base/models/fields_piyin.py
T
2025-09-24 21:50:22 +08:00

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