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

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

例子:

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”模型
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模型:
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模型:
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在“变更”方法,计算方法和记录修改跟踪中仅支持一种级别的“关系”。

因此,开箱即用,允许“父/子”设置(如FORMVIEW.one2manyLIST),但不允许“祖 parent / parent /子”(如FORMVIEW.one2manyLIST.one2manyLIST)。

例如:

  • 模型A-表示为服务保修表(祖 parent 模型)
  • 模型B-涵盖位置的列表(父模型,并引用祖 parent )
  • 模型C-为每个覆盖的位置提供的服务列表(子模型,并引用父模型)

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

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

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

    这是Odoo 8.0的代码。 YMMV与其他版本。

    FIELDS.PY/_RelationalMulti类别。替换以下方法:
    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类中,替换以下方法:
    @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
    

    关于python - 如何在Odoo中浏览或搜索One2many字段?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26124674/

    10-12 21:08