1.问题描述

当我们使用mapped函数时,我们会给函数传一个odoo模型的字段参数字符串,例如:

1
2
3
4
5
6
7
so = self.env['sale.order'].sudo().search([(id, '=', 212574)])

so.mapped('name')
Out[1]: [u'SO155168440244263003']  # 输出

so.mapped('partner_id')
Out[2]: res.partner(778648,)
  • 当传入的字段属性不是关联外键时,它会输出一个字段值列表,当传入的字段属性是外键时,它会返回关联的外键对象集合

或者,我们会传入多个字符串参数以点号分开,例如

1
2
3
4
5
so.mapped('partner_id.name')
Out[3]: [u'\u978d\u94a2\u7eff\u8272\u8d44\u6e90\u79d1\u6280\u6709\u9650\u516c\u53f8']

so.mapped('order_line.order_id')
Out[4]: sale.order(212574,)
  • 与上面一样,传入关联字段的属性也遵循这个原则

那么你有没有想过odoo处理这种数据的原理是什么呢???

2.源码及版本说明

版本:

odoo9

python2.7

贴出源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def _mapped_func(self, func):
    """ 
    将函数“func”应用于“self”中的所有记录,并将结果作为列表或记录集返回(如果“func”返回记录集)。
    """
    if self:
        vals = [func(rec) for rec in self]
        if isinstance(vals[0], BaseModel):
            # return the union of all recordsets in O(n)
            ids = set(itertools.chain(*[rec._ids for rec in vals]))
            return vals[0].browse(ids)
        return vals
    else:
        vals = func(self)
        return vals if isinstance(vals, BaseModel) else []

def mapped(self, func):
    """
    将“func”应用于“self”中的所有记录,并将结果作为列表或记录集返回(如果“func”返回记录集)。在后一种情况下,返回的记			    录集的顺序是任意的。

    :param func: 一个函数或一系列用点分隔的字段名
    """
    if isinstance(func, basestring):
        recs = self
        for name in func.split('.'):
            recs = recs._mapped_func(operator.itemgetter(name))
        return recs
    else:
        return self._mapped_func(func)

3.itemgetter函数的作用

1
2
3
from operator import itemgetter

f = itemgetter(2)

此时,调用f(r)等于调用r(2)

注意:itemgetter是调用 __gititem__ 方法来获取属性,所以对函数对象无法使用

4.代码解析

当参数是字符串时

  • 对参数字符串进行切片,然后使用_mapped_func函数循环处理参数

  • _mapped_func函数中,列表推导式中对resc对象也就是self对象循环调用 func(rec)。 假设你写的是mapped('name'),那么在此时,就会遍历self对象,获取name属性,类似于 self.__getitem__['name'], 而不是func('name')

  • 当你写的参数取出来的值是BaseModel的实例时,遍历self对象,最后获取所有的实例对象并返回,这就是为什么写关联字段的值,得到关联对象集合的原因。

当参数不是字符串的时候

  • 直接对func参数,调用_mapped_func方法

  • self对象进行循环处理,最后还是返回列表或者对象集

当非实例对象调用时

非实例对象调用时,例如 类对象

参数可以直接对类对象进行操作

举个例子:

1
2
3
4
5
so = self.env['sale.order'].sudo()

so.mapped(lambda self: self.search([('id', =, 92249)]))

Out[5]: sale.order(92249,)
  • 当self是空时

当self是空值时,等同于 类对象直接调用 mapped 方法

与上面的例子重合