为什么我只发送了一个 ID 却收到错误 "Expected singleton"?
Why do I get the error "Expected singleton" in spite of sending only one id?
我向模型添加了一些字段 stock.move
并导入了 CSV 文件以创建一些记录。我遍历了所有行,并一条一条地创建了记录,您可以在此处看到:
lot_id = self._get_lot_id(
n, row, product_id, picking_type_id,
box_quantity, product_uom_qty
)
move = {
'auto_lot_name': False,
'box_quantity': 2,
'client_order_ref': '581002',
'date': datetime.datetime(2017, 6, 24, 19, 55, 52, 372648),
'invoice_state': '2binvoiced',
'location_dest_id': 9,
'location_id': 12,
'name': 'Product name',
'partner_id': 487,
'partner_shipping_id': 488,
'picking_type_id': 2,
'price_unit': 4.0,
'pricelist_id': 1,
'product_code': u'36033',
'product_id': 3,
'product_uom': 3,
'product_uom_qty': 6.0,
'restrict_lot_id': 12222, # lot_id
'tax_id': [(4, 67)]
}
result = self.env['stock.move'].create(move)
如果需要,我会在方法 _get_lot_id
中创建批次。如果地块已经创建,我 return id。这很好用
它非常简单并且多次运行良好,但有时我会收到以下错误,尽管我只使用一个 id 填充字段 restrict_lot_id
,正如您在字典中看到的那样。看起来它正在附加上一个循环的批号。这怎么可能?我的数据库坏了吗?
File "/[ ... ]/import_moves/models/stock_picking_import_wizard.py", line 129, in _generate_moves_from_csv
result = self.env['stock.move'].create(move)
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/api.py", line 508, in new_api
result = method(self._model, cr, uid, *args, **old_kwargs)
File "/[ ... ]/stock/stock.py", line 1993, in create
res = super(stock_move, self).create(cr, uid, vals, context=context)
File "/[ ... ]/openerp/api.py", line 268, in wrapper
return old_api(self, *args, **kwargs)
File "/[ ... ]/openerp/api.py", line 372, in old_api
result = method(recs, *args, **kwargs)
File "/[ ... ]/connector/producer.py", line 48, in create ##> strange because this module is not installed
record_id = create_original(self, vals)
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/models.py", line 4126, in create
record = self.browse(self._create(old_vals))
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/api.py", line 508, in new_api
result = method(self._model, cr, uid, *args, **old_kwargs)
File "/[ ... ]/openerp/models.py", line 4323, in _create
recs._validate_fields(vals)
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/models.py", line 1285, in _validate_fields
raise ValidationError("Error while validating constraint\n\n%s" % tools.ustr(e))
ValidationError: ('ValidateError', u'Error while validating constraint\n\nValueError\nExpected singleton: stock.production.lot(12286, 12287)')
我还验证了 id 在 stock
模块中的原始 create
函数中很好地到达。
这对我来说没有任何意义。发生了什么事?
我刚刚检查过,如果我总是创建批次,那么它运行良好。所以我在这里展示的方法_get_lot_id
肯定有问题
def _get_lot_id(self, n, row, product_id,
picking_type_id, box_quantity, product_uom_qty):
lot_id_name = row.get('lot_id_name', False)
if lot_id_name != '':
if picking_type_id == STOCK_PICKING_TYPE_OUT:
lot_ids = self.env['stock.production.lot'].search([
('product_id', '=', product_id.id),
('name', '=', lot_id_name)
])
if len(lot_ids) == 0:
try:
lot_id = self.env['stock.production.lot'].create({
'name': lot_id_name,
'product_id': product_id.id,
})
except Exception:
raise Warning(_('The lot could not be created. '
'\nROW: %s') % n)
return lot_id.ensure_one().id
if len(lot_ids) == 1:
return lot_ids[0].id
else:
raise Warning(_('ERROR\nThere is more than one lot with the same name for that product.'
'\nROW: %s') % n)
elif picking_type_id == STOCK_PICKING_TYPE_IN:
lot_ids = self.env['stock.production.lot'].search([
('product_id', '=', product_id.id),
('name', '=', lot_id_name)
])
if len(lot_ids) == 1:
return lot_ids[0].id
try:
lot_id = self.env['stock.production.lot'].create({
'name': lot_id_name,
'product_id': product_id.id,
})
return lot_id.id
except Exception:
raise Warning(_('The lot could not be created. '
'\nROW: %s') % n)
else:
if picking_type_id == STOCK_PICKING_TYPE_OUT:
raise Warning(_('The lot is required for outgoing moves. '
'\nROW: %s') % n)
elif picking_type_id == STOCK_PICKING_TYPE_IN:
# set "auto_lot_name = True" >> this is set by default, so the lot is automatically created
return False
可能 create
方法已被某些自定义(或非自定义)模块覆盖,该模块修改传递给创建函数的值。
找出正在发生的事情的一种方法是转到 stock.production.lot
模型 (addons/stock/stock.py) 的 create
方法的定义,然后引发异常或 import traceback;traceback.print_stack()
查看调用的方法。之后你可以看到改变你的值的那个。
如果不是这种情况,您必须与我们分享更多代码以了解发生了什么以及您如何创建 move
字典
我认为问题出在您的某个代码中。
让我解释一下为什么这个错误会发生在 Odoo 方法中 self
是一个 recordSet
,意味着它可以包含一个或多个记录。当你使用装饰器
@api.multi
、depends
或 constraints
这里 self
可以包含多个记录,因此要避免此类错误,请确保 loop
到 self
.
for rec in self:
# your code here
# always access to rec fields not self here
如果你在执行 self.some_field
时不循环,当 recordset
只有一个记录时,这会很好地工作,但是当你有更多记录时,这会混淆你想要获得的值的记录some_field
从这里你会得到这个错误。
但是当你使用装饰器@api.one
时,这里会为每条记录调用方法,api.one
永远不会发生单例错误,因为self总是包含一条记录。
终于找到错误了。正如@Cherif Odoo 所说,错误出在计算字段中。我有这个方法
@api.multi
@api.depends('incoming_moves', 'incoming_moves.box_quantity')
def _compute_in_box_vqty(self):
for lot in self:
lot.in_box_vqty = sum(
move.box_quantity for move in self.incoming_moves)
我不得不像这样用 lot
替换 self
@api.multi
@api.depends('incoming_moves', 'incoming_moves.box_quantity')
def _compute_in_box_vqty(self):
for lot in self:
lot.in_box_vqty = sum(
move.box_quantity for move in lot.incoming_moves)
我没有早点发现错误,因为堆栈跟踪不是很有用。我在评论方法、字段、约束、创建...后找到了它...
我向模型添加了一些字段 stock.move
并导入了 CSV 文件以创建一些记录。我遍历了所有行,并一条一条地创建了记录,您可以在此处看到:
lot_id = self._get_lot_id(
n, row, product_id, picking_type_id,
box_quantity, product_uom_qty
)
move = {
'auto_lot_name': False,
'box_quantity': 2,
'client_order_ref': '581002',
'date': datetime.datetime(2017, 6, 24, 19, 55, 52, 372648),
'invoice_state': '2binvoiced',
'location_dest_id': 9,
'location_id': 12,
'name': 'Product name',
'partner_id': 487,
'partner_shipping_id': 488,
'picking_type_id': 2,
'price_unit': 4.0,
'pricelist_id': 1,
'product_code': u'36033',
'product_id': 3,
'product_uom': 3,
'product_uom_qty': 6.0,
'restrict_lot_id': 12222, # lot_id
'tax_id': [(4, 67)]
}
result = self.env['stock.move'].create(move)
如果需要,我会在方法 _get_lot_id
中创建批次。如果地块已经创建,我 return id。这很好用
它非常简单并且多次运行良好,但有时我会收到以下错误,尽管我只使用一个 id 填充字段 restrict_lot_id
,正如您在字典中看到的那样。看起来它正在附加上一个循环的批号。这怎么可能?我的数据库坏了吗?
File "/[ ... ]/import_moves/models/stock_picking_import_wizard.py", line 129, in _generate_moves_from_csv
result = self.env['stock.move'].create(move)
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/api.py", line 508, in new_api
result = method(self._model, cr, uid, *args, **old_kwargs)
File "/[ ... ]/stock/stock.py", line 1993, in create
res = super(stock_move, self).create(cr, uid, vals, context=context)
File "/[ ... ]/openerp/api.py", line 268, in wrapper
return old_api(self, *args, **kwargs)
File "/[ ... ]/openerp/api.py", line 372, in old_api
result = method(recs, *args, **kwargs)
File "/[ ... ]/connector/producer.py", line 48, in create ##> strange because this module is not installed
record_id = create_original(self, vals)
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/models.py", line 4126, in create
record = self.browse(self._create(old_vals))
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/api.py", line 508, in new_api
result = method(self._model, cr, uid, *args, **old_kwargs)
File "/[ ... ]/openerp/models.py", line 4323, in _create
recs._validate_fields(vals)
File "/[ ... ]/openerp/api.py", line 266, in wrapper
return new_api(self, *args, **kwargs)
File "/[ ... ]/openerp/models.py", line 1285, in _validate_fields
raise ValidationError("Error while validating constraint\n\n%s" % tools.ustr(e))
ValidationError: ('ValidateError', u'Error while validating constraint\n\nValueError\nExpected singleton: stock.production.lot(12286, 12287)')
我还验证了 id 在 stock
模块中的原始 create
函数中很好地到达。
这对我来说没有任何意义。发生了什么事?
我刚刚检查过,如果我总是创建批次,那么它运行良好。所以我在这里展示的方法_get_lot_id
肯定有问题
def _get_lot_id(self, n, row, product_id,
picking_type_id, box_quantity, product_uom_qty):
lot_id_name = row.get('lot_id_name', False)
if lot_id_name != '':
if picking_type_id == STOCK_PICKING_TYPE_OUT:
lot_ids = self.env['stock.production.lot'].search([
('product_id', '=', product_id.id),
('name', '=', lot_id_name)
])
if len(lot_ids) == 0:
try:
lot_id = self.env['stock.production.lot'].create({
'name': lot_id_name,
'product_id': product_id.id,
})
except Exception:
raise Warning(_('The lot could not be created. '
'\nROW: %s') % n)
return lot_id.ensure_one().id
if len(lot_ids) == 1:
return lot_ids[0].id
else:
raise Warning(_('ERROR\nThere is more than one lot with the same name for that product.'
'\nROW: %s') % n)
elif picking_type_id == STOCK_PICKING_TYPE_IN:
lot_ids = self.env['stock.production.lot'].search([
('product_id', '=', product_id.id),
('name', '=', lot_id_name)
])
if len(lot_ids) == 1:
return lot_ids[0].id
try:
lot_id = self.env['stock.production.lot'].create({
'name': lot_id_name,
'product_id': product_id.id,
})
return lot_id.id
except Exception:
raise Warning(_('The lot could not be created. '
'\nROW: %s') % n)
else:
if picking_type_id == STOCK_PICKING_TYPE_OUT:
raise Warning(_('The lot is required for outgoing moves. '
'\nROW: %s') % n)
elif picking_type_id == STOCK_PICKING_TYPE_IN:
# set "auto_lot_name = True" >> this is set by default, so the lot is automatically created
return False
可能 create
方法已被某些自定义(或非自定义)模块覆盖,该模块修改传递给创建函数的值。
找出正在发生的事情的一种方法是转到 stock.production.lot
模型 (addons/stock/stock.py) 的 create
方法的定义,然后引发异常或 import traceback;traceback.print_stack()
查看调用的方法。之后你可以看到改变你的值的那个。
如果不是这种情况,您必须与我们分享更多代码以了解发生了什么以及您如何创建 move
字典
我认为问题出在您的某个代码中。
让我解释一下为什么这个错误会发生在 Odoo 方法中 self
是一个 recordSet
,意味着它可以包含一个或多个记录。当你使用装饰器
@api.multi
、depends
或 constraints
这里 self
可以包含多个记录,因此要避免此类错误,请确保 loop
到 self
.
for rec in self:
# your code here
# always access to rec fields not self here
如果你在执行 self.some_field
时不循环,当 recordset
只有一个记录时,这会很好地工作,但是当你有更多记录时,这会混淆你想要获得的值的记录some_field
从这里你会得到这个错误。
但是当你使用装饰器@api.one
时,这里会为每条记录调用方法,api.one
永远不会发生单例错误,因为self总是包含一条记录。
终于找到错误了。正如@Cherif Odoo 所说,错误出在计算字段中。我有这个方法
@api.multi
@api.depends('incoming_moves', 'incoming_moves.box_quantity')
def _compute_in_box_vqty(self):
for lot in self:
lot.in_box_vqty = sum(
move.box_quantity for move in self.incoming_moves)
我不得不像这样用 lot
替换 self
@api.multi
@api.depends('incoming_moves', 'incoming_moves.box_quantity')
def _compute_in_box_vqty(self):
for lot in self:
lot.in_box_vqty = sum(
move.box_quantity for move in lot.incoming_moves)
我没有早点发现错误,因为堆栈跟踪不是很有用。我在评论方法、字段、约束、创建...后找到了它...