我使用Openerp 7.0,我想覆盖定义如下的函数__compute:
class account_account(osv.osv):
_name = "account.account"
_description = "Account"
def __compute(self, cr, uid, ids, field_names, arg=None, context=None,
query='', query_params=()):
""" compute the balance, debit and/or credit for the provided
account ids
Arguments:
`ids`: account ids
`field_names`: the fields to compute (a list of any of
'balance', 'debit' and 'credit')
`arg`: unused fields.function stuff
`query`: additional query filter (as a string)
`query_params`: parameters for the provided query string
(__compute will handle their escaping) as a
tuple
"""
mapping = {
'balance': "COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) as balance",
'debit': "COALESCE(SUM(l.debit), 0) as debit",
'credit': "COALESCE(SUM(l.credit), 0) as credit",
# by convention, foreign_balance is 0 when the account has no secondary currency, because the amounts may be in different currencies
'foreign_balance': "(SELECT CASE WHEN currency_id IS NULL THEN 0 ELSE COALESCE(SUM(l.amount_currency), 0) END FROM account_account WHERE id IN (l.account_id)) as foreign_balance",
}
#get all the necessary accounts
children_and_consolidated = self._get_children_and_consol(cr, uid, ids, context=context)
#compute for each account the balance/debit/credit from the move lines
accounts = {}
res = {}
null_result = dict((fn, 0.0) for fn in field_names)
if children_and_consolidated:
aml_query = self.pool.get('account.move.line')._query_get(cr, uid, context=context)
wheres = [""]
if query.strip():
wheres.append(query.strip())
if aml_query.strip():
wheres.append(aml_query.strip())
filters = " AND ".join(wheres)
# IN might not work ideally in case there are too many
# children_and_consolidated, in that case join on a
# values() e.g.:
# SELECT l.account_id as id FROM account_move_line l
# INNER JOIN (VALUES (id1), (id2), (id3), ...) AS tmp (id)
# ON l.account_id = tmp.id
# or make _get_children_and_consol return a query and join on that
request = ("SELECT l.account_id as id, " +\
', '.join(mapping.values()) +
" FROM account_move_line l" \
" WHERE l.account_id IN %s " \
+ filters +
" GROUP BY l.account_id")
params = (tuple(children_and_consolidated),) + query_params
cr.execute(request, params)
for row in cr.dictfetchall():
accounts[row['id']] = row
# consolidate accounts with direct children
children_and_consolidated.reverse()
brs = list(self.browse(cr, uid, children_and_consolidated, context=context))
sums = {}
currency_obj = self.pool.get('res.currency')
while brs:
current = brs.pop(0)
for fn in field_names:
sums.setdefault(current.id, {})[fn] = accounts.get(current.id, {}).get(fn, 0.0)
for child in current.child_id:
if not child.active:
continue
if child.company_id.currency_id.id == current.company_id.currency_id.id:
try:
sums[current.id][fn] += sums[child.id][fn]
except:
sums[current.id][fn] += accounts.get(child.id, {}).get(fn, 0.0)
else:
sums[current.id][fn] += currency_obj.compute(cr, uid, child.company_id.currency_id.id, current.company_id.currency_id.id, sums[child.id][fn], context=context)
# as we have to relay on values computed before this is calculated separately than previous fields
if current.currency_id and current.exchange_rate and \
('adjusted_balance' in field_names or 'unrealized_gain_loss' in field_names):
# Computing Adjusted Balance and Unrealized Gains and losses
# Adjusted Balance = Foreign Balance / Exchange Rate
# Unrealized Gains and losses = Adjusted Balance - Balance
adj_bal = sums[current.id].get('foreign_balance', 0.0) / current.exchange_rate
sums[current.id].update({'adjusted_balance': adj_bal, 'unrealized_gain_loss': adj_bal - sums[current.id].get('balance', 0.0)})
for id in ids:
res[id] = sums.get(id, null_result)
else:
for id in ids:
res[id] = null_result
return res
account_account()
我读到当你想要覆盖带有双下划线的函数时,你在方法名称前加一个下划线,并将定义的类名称作为以下内容:
def _account_account__compute(self, cr, uid, ids, field_names, arg=None, context=None,
query='', query_params=()):
但它不起作用。
答案 0 :(得分:2)
您阅读的内容是由于name mangling,双下划线前缀方法变为私有。此过程重写类定义中的名称以指向新名称。新名称按照您的说法构建:_<class name><class method name>
。请考虑以下示例:
class A():
def public(self): print('public() called')
def _internal_use(self): print('_internal_use() called')
def __private(self): print('__private() called')
def f(self): self.__private()
现在让我们看看A.__dict__
,它是按名称存储方法的结构:
>>> A.__dict__
mappingproxy({
'f': <function A.f at 0x1028908c8>,
'_A__private': <function A.__private at 0x1028906a8>,
'_internal_use': <function A._internal_use at 0x102890620>,
'__weakref__': <attribute '__weakref__' of 'A' objects>,
'__dict__': <attribute '__dict__' of 'A' objects>,
'__module__': '__main__',
'__doc__': None,
'public': <function A.public at 0x102890598>
})
除其他外,请注意您有_A__private
,_internal_use
和public
。
请注意,这些名称在模块范围内不存在,它们仅存在于类的__dict__
内。当Python解析成员访问时,它会查看对象的__dict__
内部。如果不是fount,它会调查班级&#39; __dict__
和超级班级&#39; __dict__
。
a = A()
a.public
# Python looks into a.__dict__. If not found, it looks into type(a).__dict__
这样您就可以访问public
或_internal_use
,但找不到__private
,因为该名称甚至不存在。您可以访问的是_A__private
:
a.public # works
a.f # works
a._internal_use # works
a.__private # AttributeError!
a._A__private # works again
请注意,这两个名称都没有在模块全局范围中定义:
public # NameError!
_internal_use # NameError!
__private # NameError!
_A__private # NameError!
但是您尝试通过简单地定义具有该名称的模块函数来覆盖该函数。好吧,Python成员访问解析永远不会涉及全局范围。所以你有几个选择:
您可以创建另一个继承类并重新定义该函数:
class B(A):
def _A__private(self): print('New __private() called')
a = A()
a.f() # prints __private() called
b = B()
b.f() # prints New __private() called
您可以直接使用任何其他函数(甚至是lambda)覆盖该方法:
A._A__private = lambda self: print('This is a lambda')
a = A()
a.f() # prints This is a lambda
答案 1 :(得分:0)
您需要创建继承自odoo类的account_account类。然后,您可以使用super():
覆盖方法class stock_move(osv.osv):
_inherit = "account.account"
# new columns
# ...
def __compute(self, cr, uid, ids, field_names, arg=None, context=None,
query='', query_params=()):
# do your stuff
# call parent method if needed
return super(stock_move, self).__compute(self, cr, uid, ids, field_names, arg=None, context=None, query='', query_params=())
这是一个示例,覆盖一个非常常见的create方法,因为您可能希望在创建对象时添加一些额外的功能:
class mrp_product_produce(osv.osv_memory):
_inherit = "mrp.product.produce"
def create(self, cr, uid, vals, context=None):
res ={}
res = super(product_product, self).create(cr, uid, vals, context)
if 'supply_method' in vals and vals['supply_method'] == 'produce':
sequence_type_obj = self.pool.get('ir.sequence.type')
id_type = sequence_type_obj.create(cr, uid, {'name': vals['name'], 'code': 'product_produce_' + str(res)})
sequence_obj = self.pool.get('ir.sequence')
sequence_obj.create(cr, uid, {'name': vals['name'], 'code': 'product_produce_' + str(res), 'padding': 7, 'number_increment': 1, 'number_next': 1 })
return res