- Published on
修复 Odoo 的一个 bug
- Authors
- Name
- Alex
- @adams6688
在使用 Odoo 的时候,发现 Odoo 的一个 bug,这里贴出来。
先来看一段odoo的代码(addons/product/models/product.py
):
@api.multi
def unlink(self):
unlink_products = self.env['product.product']
unlink_templates = self.env['product.template']
for product in self:
# Check if product still exists, in case it has been unlinked by unlinking its template
if not product.exists():
continue
# Check if the product is last product of this template...
other_products = self.search([('product_tmpl_id', '=', product.product_tmpl_id.id), ('id', '!=', product.id)])
# ... and do not delete product template if it's configured to be created "on demand"
if not other_products and not product.product_tmpl_id.has_dynamic_attributes():
unlink_templates |= product.product_tmpl_id
unlink_products |= product
res = super(ProductProduct, unlink_products).unlink()
# delete templates after calling super, as deleting template could lead to deleting
# products due to ondelete='cascade'
unlink_templates.unlink()
return res
这段代码的作用是在删除商品的时候,去检查商品模板,如果商品模板没有关联的其它商品,那么就把商品模板一起删掉,正常情况下,这是没有问题的。
但是,这里有考虑不周到的地方,如果一个产品有多个变体,当其中的一个变体已经归档的话,other_products = self.search([('product_tmpl_id', '=', product.product_tmpl_id.id), ('id', '!=', product.id)])
这条语句是查不出来已经归档的变体的,从而导致在删除 templates 造成数据库约束错误。
正确的做法如下所示:
@api.multi
def unlink(self):
unlink_products = self.env['product.product']
unlink_templates = self.env['product.template']
for product in self:
# Check if product still exists, in case it has been unlinked by unlinking its template
if not product.exists():
continue
# Check if the product is last product of this template...
other_products = self.search([('product_tmpl_id', '=', product.product_tmpl_id.id), ('id', '!=', product.id), \
'|', ('active', '=', False), ('active', '=', True)])
# ... and do not delete product template if it's configured to be created "on demand"
if not other_products and not product.product_tmpl_id.has_dynamic_attributes():
unlink_templates |= product.product_tmpl_id
unlink_products |= product
res = super(ProductProduct, unlink_products).unlink()
# delete templates after calling super, as deleting template could lead to deleting
# products due to ondelete='cascade'
unlink_templates.unlink()
return res
遵循最小改动原则,只需要把查询搞成 other_products = self.search([('product_tmpl_id', '=', product.product_tmpl_id.id), ('id', '!=', product.id), '|', ('active', '=', False), ('active', '=', True)])
即可。
向 Odoo 官方提交了一个 : PR
后来,还有一种更好的做法:
other_products = self.env['product.product'].with_context(active_test=False).\
search([('product_tmpl_id', '=', product.product_tmpl_id.id), ('id', 'not in', self.ids)])
这种写法看起来更好。
时间线
发布日期:2018-12-25
最后修改日期:2019-03-14