1

我正在开发一个 Odoo 模块,在该模块中,我没有直接在模型中定义字段,而是有一个名为 schema 的元组,它包含所有字段。我在模型中定义了一个类方法,它从元组中读取每个字段并通过自省在模型上创建它。

@classmethod
def initialze(cls, schema):
    for field in schema:
        add_a_field(cls, field)
        pass
    pass       

可以看出,此方法在元组上进行迭代并将单个字段传递给另一个方法名称“add_a_field(cls, field)”。

方法 'add_a_field' 使用 python setattr() 内置方法。

def add_a_field(cls, field):
    setattr(cls, field.string, field)
    pass

它添加了一个具有相同名称和标签的字段。

在我有这个方法的类中,我直接调用它,如下例所示:

from openerp import fields, models
# other imports

def add_a_field(cls, field):
    setattr(cls, field.string, field)
    pass

schema = (
          fields.Char(string='RequestID'),
          fields.Float(string='Discount', default=0.00),
          fields.Float(string='Subtotal', default=0.00),
          )

class Batch(models.Model): 
    _name='batch'
    @classmethod
    def initialze(cls, schema):
        for field in schema:
            add_a_field(cls, field)
            pass
        pass       
    pass

# other model methods
Batch.initialze(schema)

在 Odoo v8 中它工作正常,但在 v9 中它给出一个错误''RuntimeError: maximum recursion depth exceeded'</p>

在 Odoo v9 fields.py __getattr__ 定义如下(参见https://github.com/odoo/odoo/blob/9.0/openerp/fields.py):

def __getattr__(self, name):
    """ Access non-slot field attribute. """
    try:
        return self._attrs[name]
    except KeyError:
        raise AttributeError(name)

而 __init__ 如下:

def __init__(self, string=None, **kwargs):
        kwargs['string'] = string
        args = {key: val for key, val in kwargs.iteritems() if val is not None}
        self.args = args or EMPTY_DICT
        self.setup_full_done = False

在 v8 fields.py 中,__init__ 定义如下:

def __init__(self, string=None, **kwargs):
        kwargs['string'] = string
        attrs = {key: val for key, val in kwargs.iteritems() if val is not None}
        self._attrs = attrs or EMPTY_DICT

错误是:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in initialze
  File "<stdin>", line 2, in add_a_field
  File "openerp/fields.py", line 343, in __getattr__
    return self._attrs[name]
  File "openerp/fields.py", line 343, in __getattr__
    return self._attrs[name]
  File "openerp/fields.py", line 343, in __getattr__
    return self._attrs[name]
  File "openerp/fields.py", line 343, in __getattr__
    return self._attrs[name]
  File "openerp/fields.py", line 343, in __getattr__
    return self._attrs[name]
:
:
:
:
RuntimeError: maximum recursion depth exceeded while calling a Python object

知道这应该如何解决吗?

4

1 回答 1

1

经过一些调试并在fields.py中查看后,很明显 Odoo 不再希望模块/应用程序代码使用点符号访问初始化参数,也就是 init 参数,因此使用 field.string 来访问字段或 field.required 的名称找出这个字段是否是必需的,它不再是一段有效的代码。取而代之的是,现在应该从名为 args 的字典类型字段实例变量中访问所有初始化参数。

当我在以下代码中访问 field.string 时,出现了运行时错误:

def add_a_field(cls, field):
    setattr(cls, field.string, field)
    pass

我现在修改了代码如下:

def add_a_field(cls, field):
    setattr(cls, field.args['string'], field)
    pass

args 和 _attrs 在fields.py中定义如下:

_slots = {
    'args': EMPTY_DICT,             # the parameters given to __init__()
    '_attrs': EMPTY_DICT,           # the field's non-slot attributes

而早期在Odoo v8中没有 args,而 _attrs 定义如下:

_slots = {
    '_attrs': EMPTY_DICT,           # dictionary of field attributes; it contains:
                                    #  - all attributes after __init__()
                                    #  - free attributes only after set_class_name()

所以总而言之,模块/应用程序代码现在应该直接使用field.args['string'] 或 field.args['required']而不是点符号,即 field.string 或 field.required

于 2015-11-07T12:21:02.680 回答