如何在Odoo中浏览或搜索One2many字段? [英] How to browse or search One2many field in Odoo?

查看:86
本文介绍了如何在Odoo中浏览或搜索One2many字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经用One2many字段扩展了"account.analytic.account"模型,该模型引用了另一个具有One2many字段的模型.

I've extended the 'account.analytic.account' model with a One2many field that references a second model with a One2many field.

当我尝试遍历计算方法中的第二个One2many字段时,它仅列出刚添加的记录.在保存父记录之前,以前的记录(在界面上可见)在使用自我"上下文的代码中不可见.

When I try to iterate through the second One2many field from the compute method it only lists records that have just been added. Previous records (which are visible on the interface) are not visible in code using the 'self' context until the parent record is saved.

示例:

for line in self.One2manyField:
    #only gets here for records I add during current session, or all records if parent is saved
    #how can I see previously saved records? 

这是代码:

1.)扩展的"account.analytic.account"模型

1.) extended 'account.analytic.account' model

class account_analytic_account(models.Model):

    _inherit = ['account.analytic.account']

    service_location_ids = fields.One2many(comodel_name='contract.service.location', inverse_name='contract_id', copy=True)

2.)首先引用一个One2many模型:

2.) First referenced One2many model:

class Contract_Service_Location(models.Model):
    _name = 'contract.service.location'
    _description = 'Service Location Record'  

    #problem is here!
    #compute method for subtotal field
    @api.one    
    @api.depends('recurring_line_ids','recurring_line_ids.price_subtotal')
    def _compute_subtotal(self):
        total = 0.0

        #I tried to get previously saved ids, but returns nothing, until parent record is saved
        old_ids = self.env['contract.recurring.line'].search([('service_location_id', '=', self.id)]) 

        #this only works for new entries during same session, or until parent record is saved. Why?
        for line in self.recurring_line_ids:
            total = total + line.price_subtotal

        #set field
        self.price_subtotal = total

    contract_id = fields.Many2one(comodel_name='account.analytic.account')
    fiscal_position = fields.Many2one(comodel_name='account.fiscal.position', string='Default Taxes')
    partner_id = fields.Many2one(comodel_name='res.partner', string='Service Location', help='Optional seperate billing address from customer AND service locations',required=True)
    sequence = fields.Integer(string='Sequence', help="Gives the sequence order when displaying a list of sales order lines.")
    price_subtotal = fields.Float(compute='_compute_subtotal', string='Subtotal', digits_compute= dp.get_precision('Account'), readonly=True, store=True)
    pricelist_id = fields.Many2one(comodel_name='product.pricelist', string='Pricelist', required=True, help="Pricelist for current customer.", default=_get_default_pricelist)
    recurring_line_ids = fields.One2many(comodel_name='contract.recurring.line', inverse_name='service_location_id', copy=True)

3.)第二个引用的One2many模型:

3.) Second referenced One2many model:

class Contract_Recurring_Line(models.Model):
    _name = 'contract.recurring.line'
    _description = 'Recurring Service Location Line'


    @api.one
    @api.depends('price_unit', 'discount', 'product_uom_qty','product_uos_qty',
        'product_id', 'service_location_id.partner_id','service_location_id.pricelist_id')
    def _compute_subtotal(self):
        price = self.price_unit * (1 - (self.discount or 0.0) / 100.0)
        taxes = self.tax_id.compute_all(price, self.product_uom_qty, product=self.product_id, partner=self.service_location_id.partner_id)
        self.price_subtotal = taxes['total']
        if self.service_location_id:
            self.price_subtotal = self.service_location_id.pricelist_id.currency_id.round(self.price_subtotal)


    service_location_id = fields.Many2one(comodel_name='contract.service.location', required=True, ondelete='cascade', select=True)
    name = fields.Text('Description', required=True)
    product_id = fields.Many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], change_default=True, ondelete='restrict')
    price_unit = fields.Float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'))
    price_subtotal = fields.Float(compute='_compute_subtotal', string='Subtotal',store=True, readonly=True, digits_compute= dp.get_precision('Account'))
    product_uom_qty = fields.Float('Quantity', default=float(1), digits_compute= dp.get_precision('Product UoS'))
    discount = fields.Float('Discount (%)', digits_compute= dp.get_precision('Discount'))

推荐答案

不幸的是,OpenERP/Odoo仅在变更"方法,计算方法和记录修改跟踪中支持一种关系级别.

Sadly OpenERP/Odoo only supports one level of Relationship in On-change methods, compute methods, and record modification tracking.

因此,开箱即用,允许父/子"设置(如FORMVIEW.one2manyLIST),但不允许祖父母/父母/孩子(如FORMVIEW.one2manyLIST.one2manyLIST).

So out of the box, Parent/Child setups are allowed (as in FORMVIEW.one2manyLIST) but not Grandparent/Parent/Child (as in FORMVIEW.one2manyLIST.one2manyLIST).

例如:

  • 模型A-作为服务保修表(祖父母模型)出示
  • 模型B-所覆盖位置的列表(父模型,并引用祖父母)
  • 模型C-为每个覆盖地点提供的服务列表(子模型,并参考父模型)

对模型A所做的更改不会保存模型C的记录,并且模型A上的变更/计算方法不能使用模型C上的字段

Changes made to Model A will not save records of Model C, and on-change/compute methods on Model A cannot use fields on Model C

因此,如果对第二个嵌套的one2many字段进行更改,或者即使您尝试读取嵌套的one2many字段,更改也会丢失,并且会遇到上述问题.

So, changes are lost and the problem above is experienced if changes are made on the second nested one2many field, or even if you attempt to read the nested one2many field.

我创建了一个解决方案,为onchange/compute/write添加了另一级别的跟踪.您将需要修改Odoo的核心.我希望这种情况将来会有所改变,因为Odoo SA在github上将其列为愿望清单".

I have created a solution that adds another level of tracking to the onchange/compute/write. You will need to modify the core of Odoo. I hope this changes in the future as Odoo SA has this listed on github as "wishlist".

这是Odoo 8.0的代码. YMMV和其他版本.

Here is the code for Odoo 8.0. YMMV with other versions.

FIELDS.PY/_RelationalMulti类.替换以下方法:

FIELDS.PY/_RelationalMulti Class. Replace the following method:

def convert_to_write(self, value, target=None, fnames=None):
    # remove/delete former records
    if target is None:
        set_ids = []
        result = [(6, 0, set_ids)]
        add_existing = lambda id: set_ids.append(id)
    else:
        tag = 2 if self.type == 'one2many' else 3
        result = [(tag, record.id) for record in target[self.name] - value]
        add_existing = lambda id: result.append((4, id))

    if fnames is None:
        # take all fields in cache, except the inverses of self
        fnames = set(value._fields) - set(MAGIC_COLUMNS)
        for invf in self.inverse_fields:
            fnames.discard(invf.name)

    # add new and existing records
    for record in value:
        if not record.id or record._dirty:
            values = dict((k, v) for k, v in record._cache.iteritems() if k in fnames)
            tempVal = {}
            for n in values:
                f = record._fields[n] #get field def
                if f.type == 'one2many':
                    subrec = record[n]
                    subfields = subrec._fields                    
                    tempVal[n] = f.convert_to_write(subrec,record)
                else:
                    val = {}
                    val[n] = values.get(n)
                    tempVal[n] = record._convert_to_write(val)[n]

            if tempVal:
                values = tempVal       

            #add to result       
            if not record.id:
                    result.append((0, 0, values))
            else:
                result.append((1, record.id, values))
        else:
            add_existing(record.id)

    return result

在MODELS.py/BaseModel类中,替换以下方法:

In MODELS.py/BaseModel Class, replace the following method:

@api.model
def new(self, values={}):
    """ new([values]) -> record

    Return a new record instance attached to the current environment and
    initialized with the provided ``value``. The record is *not* created
    in database, it only exists in memory.
    """
    record = self.browse([NewId()])
    record._cache.update(record._convert_to_cache(values, update=True))

    if record.env.in_onchange:
        # The cache update does not set inverse fields, so do it manually.
        # This is useful for computing a function field on secondary
        # records, if that field depends on the main record.
        for name in values:
            field = self._fields.get(name)
            if field:
                try:
                    for invf in field.inverse_fields:
                        invf._update(record[name], record)

                        #serarch this field for sub inverse fields
                        for ftmp in self[name]._fields: 

                                f = self[name]._fields.get(ftmp) 
                                if f and f != invf:                  
                                    for invf in f.inverse_fields:
                                        val = record[name]
                                        invf._update(record[name][ftmp], val)

                except:
                    pass

    return record

这篇关于如何在Odoo中浏览或搜索One2many字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆