Odoo 10 - 保存后获取实际行或调用函数
Odoo 10 - Get actual row or call function after saving
我正在处理表单内的 table。 table 自动填充用户必须执行的第一个字段的输入。在 table 中,只有一列用户必须输入数据,我让他们可以直接在 table 中输入数据,而不是打开一个新表格。
这些数据需要使用 table 中隐藏的值进行检查,我只需要检查用户输入的值是否符合某些公差。
现在我的问题是,为了检查值,我需要知道值的 ID,以便能够检查权限容差,但如果用户不保存表单,我将无法获取它们。
所以我有两个问题:
是否可以在保存后立即调用函数?我知道我可以覆盖 "create" 函数,但这不是我想要的,我希望在保存后立即调用一个函数,多亏了它,我才能知道 ID 并且可以检查值.
如果那不可能,我的第二个问题是:
当用户在其中输入值时是否可以获取行号?用 api.onchange 获取行号会很有用,这样我就可以简单地循环到行中,直到找到正确的行,然后使用那里的数据。
感谢您的宝贵时间
EDIT1:这里是我循环遍历数据的代码:
class ControlMeasure(models.Model):
"""
Modèle pour la mesure d'une pièce
"""
# Nom de la table
_name = 'spc.control.measure'
# Champs de la table
name = fields.Many2one(string='Name', related='control_point_id.measure_type_id', readonly=True)
value = fields.Float(string='Measured value')
validity = fields.Boolean(string='Validity', readonly=True)
nominal_value = fields.Float(string='Nominal value', related='control_point_id.nominal_value', readonly=True)
unit_id = fields.Many2one('product.uom', string='Unit', related='control_point_id.product_uom_id', readonly=True)
control_part_id = fields.Many2one('spc.control.part', string='Controled piece')
control_point_id = fields.Many2one('spc.control.point', string='Control point')
# Champs visuels
control_device_id = fields.Many2one('spc.control.device', string='Used device', related='control_point_id.control_device_id')
# Vérifie si la valeur mesurée est dans la tolérance
@api.multi
@api.onchange('value')
def is_valid(self):
# raise Exception('Appel réussi')
sql= """
SELECT p.nominal_value, p.inferior_tolerance, p.superior_tolerance FROM spc_control_point p
WHERE p.control_plan_id = %(ctrlid)s
"""
if self.control_part_id.control_plan_id == False:
raise Exception('False ' + str(self.control_part_id.control_plan_id))
else:
self.env.cr.execute(sql, {'ctrlid' : self.control_part_id.control_plan_id.id})
row = self.env.cr.fetchall()
for i in range(0, len(row)):
#raise Exception(str(self.value) + ' < ' + str(row[i][0]) + ' - ' + str(abs(row[i][1])) + ' or ' + str(self.value) + ' > ' + str(row[i][0]) + ' + ' + str(abs(row[i][2])))
if self.value < row[i][0] - abs(row[i][1]) or self.value > row[i][0] + abs(row[i][2]):
self.validity = False
else:
self.validity = True
这里整个代码按照我想要的方式工作,除了我不知道如何正确制作它的循环,我检查了被测试的数据是否正确并且它们是正确的,测试本身像我一样工作想要,但正如您每次检查所有行和末尾时看到的那样,只有最后一行才算数。
这就是为什么我想到获取用户单击的行号的原因,但我不知道是否可以这样做,甚至不知道是否可以在保存后调用一个函数,这很容易,因为我会知道 ID 并且我可以检查保存后的数据。
我想到了两种可能的解决方案:
正如您所提到的,您可以使用 @api.onchange
装饰器创建一个方法,以在用户每次传入时检查输入的数据,而无需实际保存或进行任何其他操作。
@api.multi
@api.onchange('your_field', 'your_field2')
def _onchange_your_fields(self):
for record in self:
if record.your_field != record.validation_field:
raise exceptions.ValidationError(_('Sorry, pal, try again'))
这样做的好处是,它会快速验证字段的值:在用户将光标放在下一个字段上之后。虽然,从用户的角度来看,这可能会令人恼火。
你可以试试@api.constrains
装饰器。它的行为与 @api.onchange
装饰器略有不同,但通常将其用于验证。
@api.multi
@api.constrains('your_field', 'your_field2')
def _check_your_fields(self):
for record in self:
if record.your_field != record.validation_field:
raise exceptions.ValidationError(_('Sorry, pal, try again'))
不同之处在于它会在您点击 "Save" 按钮之后,但在实际执行 create
或 write
函数之前调用。
希望,这会有所帮助。
更新 1:
# Vérifie si la valeur mesurée est dans la tolérance
@api.multi
@api.onchange('value')
def validate(self):
# Because we are using @api.multi decorator, our 'self' is actually a recordset.
# That means, that we cannot treat it as a regular record, so "self.control_part_id...." would be an odd code
for record in self:
# So now we took a one record from recordset, and now we can continue on validating it.
if not record.control_part_id.control_plan_id:
raise exceptions.UserError(_('False %s' % str(record.control_part_id.control_plan_id)))
# You executed here a SQL query, which is actually takes our records from database, not from cache.
# But we haven't write(or create) our changes yet, and that makes no sense.
# What we wanna do, is to take values from cache and validate them. You can simply do it just via model's field
validation_record = record.control_point_id
if record.value < validation_row.nominal_value - validation_row.inferior_tolerance \
or record.value > validation_row.nominal_value + validation_row.superior_tolerance:
record.validity = True
else:
# You can get rid of this line by simply defining the default value of record.validity as "False"
record.validity = False
# I recommend you to check the final validation this way
@api.multi
@api.constrains('validity')
def check_valid(self):
for record in self:
if not record.validity:
raise exceptions.ValidationError(_("Cannot pass a validation rest"))
我正在处理表单内的 table。 table 自动填充用户必须执行的第一个字段的输入。在 table 中,只有一列用户必须输入数据,我让他们可以直接在 table 中输入数据,而不是打开一个新表格。 这些数据需要使用 table 中隐藏的值进行检查,我只需要检查用户输入的值是否符合某些公差。
现在我的问题是,为了检查值,我需要知道值的 ID,以便能够检查权限容差,但如果用户不保存表单,我将无法获取它们。
所以我有两个问题: 是否可以在保存后立即调用函数?我知道我可以覆盖 "create" 函数,但这不是我想要的,我希望在保存后立即调用一个函数,多亏了它,我才能知道 ID 并且可以检查值. 如果那不可能,我的第二个问题是: 当用户在其中输入值时是否可以获取行号?用 api.onchange 获取行号会很有用,这样我就可以简单地循环到行中,直到找到正确的行,然后使用那里的数据。
感谢您的宝贵时间
EDIT1:这里是我循环遍历数据的代码:
class ControlMeasure(models.Model):
"""
Modèle pour la mesure d'une pièce
"""
# Nom de la table
_name = 'spc.control.measure'
# Champs de la table
name = fields.Many2one(string='Name', related='control_point_id.measure_type_id', readonly=True)
value = fields.Float(string='Measured value')
validity = fields.Boolean(string='Validity', readonly=True)
nominal_value = fields.Float(string='Nominal value', related='control_point_id.nominal_value', readonly=True)
unit_id = fields.Many2one('product.uom', string='Unit', related='control_point_id.product_uom_id', readonly=True)
control_part_id = fields.Many2one('spc.control.part', string='Controled piece')
control_point_id = fields.Many2one('spc.control.point', string='Control point')
# Champs visuels
control_device_id = fields.Many2one('spc.control.device', string='Used device', related='control_point_id.control_device_id')
# Vérifie si la valeur mesurée est dans la tolérance
@api.multi
@api.onchange('value')
def is_valid(self):
# raise Exception('Appel réussi')
sql= """
SELECT p.nominal_value, p.inferior_tolerance, p.superior_tolerance FROM spc_control_point p
WHERE p.control_plan_id = %(ctrlid)s
"""
if self.control_part_id.control_plan_id == False:
raise Exception('False ' + str(self.control_part_id.control_plan_id))
else:
self.env.cr.execute(sql, {'ctrlid' : self.control_part_id.control_plan_id.id})
row = self.env.cr.fetchall()
for i in range(0, len(row)):
#raise Exception(str(self.value) + ' < ' + str(row[i][0]) + ' - ' + str(abs(row[i][1])) + ' or ' + str(self.value) + ' > ' + str(row[i][0]) + ' + ' + str(abs(row[i][2])))
if self.value < row[i][0] - abs(row[i][1]) or self.value > row[i][0] + abs(row[i][2]):
self.validity = False
else:
self.validity = True
这里整个代码按照我想要的方式工作,除了我不知道如何正确制作它的循环,我检查了被测试的数据是否正确并且它们是正确的,测试本身像我一样工作想要,但正如您每次检查所有行和末尾时看到的那样,只有最后一行才算数。 这就是为什么我想到获取用户单击的行号的原因,但我不知道是否可以这样做,甚至不知道是否可以在保存后调用一个函数,这很容易,因为我会知道 ID 并且我可以检查保存后的数据。
我想到了两种可能的解决方案:
正如您所提到的,您可以使用
@api.onchange
装饰器创建一个方法,以在用户每次传入时检查输入的数据,而无需实际保存或进行任何其他操作。@api.multi @api.onchange('your_field', 'your_field2') def _onchange_your_fields(self): for record in self: if record.your_field != record.validation_field: raise exceptions.ValidationError(_('Sorry, pal, try again'))
这样做的好处是,它会快速验证字段的值:在用户将光标放在下一个字段上之后。虽然,从用户的角度来看,这可能会令人恼火。
你可以试试
@api.constrains
装饰器。它的行为与@api.onchange
装饰器略有不同,但通常将其用于验证。@api.multi @api.constrains('your_field', 'your_field2') def _check_your_fields(self): for record in self: if record.your_field != record.validation_field: raise exceptions.ValidationError(_('Sorry, pal, try again'))
不同之处在于它会在您点击 "Save" 按钮之后,但在实际执行 create
或 write
函数之前调用。
希望,这会有所帮助。
更新 1:
# Vérifie si la valeur mesurée est dans la tolérance
@api.multi
@api.onchange('value')
def validate(self):
# Because we are using @api.multi decorator, our 'self' is actually a recordset.
# That means, that we cannot treat it as a regular record, so "self.control_part_id...." would be an odd code
for record in self:
# So now we took a one record from recordset, and now we can continue on validating it.
if not record.control_part_id.control_plan_id:
raise exceptions.UserError(_('False %s' % str(record.control_part_id.control_plan_id)))
# You executed here a SQL query, which is actually takes our records from database, not from cache.
# But we haven't write(or create) our changes yet, and that makes no sense.
# What we wanna do, is to take values from cache and validate them. You can simply do it just via model's field
validation_record = record.control_point_id
if record.value < validation_row.nominal_value - validation_row.inferior_tolerance \
or record.value > validation_row.nominal_value + validation_row.superior_tolerance:
record.validity = True
else:
# You can get rid of this line by simply defining the default value of record.validity as "False"
record.validity = False
# I recommend you to check the final validation this way
@api.multi
@api.constrains('validity')
def check_valid(self):
for record in self:
if not record.validity:
raise exceptions.ValidationError(_("Cannot pass a validation rest"))