关于ZAKER 融媒体解决方案 合作 加入

多次调用计算方法?

CocoaChina 11-20

I found out that this probably isn ’ t concurrency problem as the

method is recalled JUST WHEN I TRY TO UPDATE THE sync.test.subject.b ‘ s separated_chars FIELD ( at the end of the method ) . So

I can ’ t solve this with thread locking as the method actually waits for itself to be called again. I don ’ t get it this is a totally bizarre behavior.

更新计算字段时发现奇怪的行为 . 在这种情况下 , 代码胜于单词:

楷模:

from openerp import models, fields, api, _class sync_test_subject_a ( models.Model ) : _name = "sync.test.subject.a" name = fields.Char ( 'Name' ) sync_test_subject_a ( ) class sync_test_subject_b ( models.Model ) : _name = "sync.test.subject.b" chars = fields.Char ( 'Characters' ) separated_chars = fields.Many2many ( 'sync.test.subject.a',string='Separated Name', store=True, compute='_compute_separated_chars' ) @api.depends ( 'chars' ) def _compute_separated_chars ( self ) : print "CHAR SEPARATION BEGIN" sync_test_subject_a_pool = self.env [ 'sync.test.subject.a' ] print "SEPARATE CHARS" # SEPARATE CHARS characters = [ ] if self.chars: for character in self.chars: characters.append ( character ) print "DELETE CURRENT CHARS" # DELETE CURRENT MANY2MANY LINK self.separated_chars.unlink ( ) print "DELETE EXISTING sync_test_subject_a THAT ARE RELATED TO CURRENT SELF" # DELETE EXISTING sync_test_subject_a THAT ARE RELATED TO CURRENT SELF deleted_separated_char_ids = [ ] for separated_char in self.separated_chars: deleted_separated_char_ids.append ( separated_char.sync_test_subject_a_id.id ) sync_test_subject_a_pool.browse ( deleted_separated_char_ids ) .unlink ( ) print "INSERT NEW CHAR RECORDS" #INSERT NEW CHAR RECORDS separated_char_ids = [ ] for character in characters: separated_char_ids.append ( sync_test_subject_a_pool.create ( {'name':character} ) .id ) print "UPDATE self.separated_chars WITH CHAR IDS" #UPDATE self.separated_chars WITH CHAR IDS self.separated_chars = separated_char_ids print "CHAR SEPARATION END"sync_test_subject_b ( ) class sync_test_subject_c ( models.Model ) : _name = "sync.test.subject.c" _inherit = "sync.test.subject.b" name = fields.Char ( 'Name' ) @api.one def action_set_char ( self ) : self.chars = self.namesync_test_subject_c ( )

观看次数:

<?xml version="1.0" encoding="UTF-8"?><openerp> <data> <!-- Top menu item --> <menuitem name="Testing Module" id="testing_module_menu" sequence="1"/> <menuitem id="sync_test_menu" name="Synchronization Test" parent="testing_module_menu" sequence="1"/> <!--Expense Preset View--> <record model="ir.ui.view" id="sync_test_subject_c_form_view"> <field name="name">sync.test.subject.c.form.view</field> <field name="model">sync.test.subject.c</field> <field name="type">form</field> <field name="arch" type="xml"> <form string="Sync Test" version="7.0"> <header> <div class="header_bar"> <button name="action_set_char" string="Set Name To Chars" type="object" class="oe_highlight"/> </div> </header> <sheet> <group> <field string="Name" name="name" class="oe_inline"/> <field string="Chars" name="chars" class="oe_inline"/> <field string="Separated Chars" name="separated_chars" class="oe_inline"/> </group> </sheet> </form> </field> </record> <record model="ir.ui.view" id="sync_test_subject_c_tree_view"> <field name="name">sync.test.subject.c.tree.view</field> <field name="model">sync.test.subject.c</field> <field name="type">tree</field> <field name="arch" type="xml"> <tree string="Class"> <field string="Name" name="name"/> </tree> </field> </record> <record model="ir.ui.view" id="sync_test_subject_c_search"> <field name="name">sync.test.subject.c.search</field> <field name="model">sync.test.subject.c</field> <field name="type">search</field> <field name="arch" type="xml"> <search string="Sync Test Search"> <field string="Name" name="name"/> </search> </field> </record> <record id="sync_test_subject_c_action" model="ir.actions.act_window"> <field name="name">Sync Test</field> <field name="res_model">sync.test.subject.c</field> <field name="view_type">form</field> <field name="domain"> [ ] </field> <field name="context">{}</field> <field name="view_id" eval="sync_test_subject_c_tree_view"/> <field name="search_view_id" ref="sync_test_subject_c_search"/> <field name="target">current</field> <field name="help">Synchronization Test</field> </record> <menuitem action="sync_test_subject_c_action" icon="STOCK_JUSTIFY_FILL" sequence="1" id="sync_test_subject_c_action_menu" parent="testing_module.sync_test_menu" /> </data></openerp>

共有 3 个类 , 即 sync.test.subject.a 与与 sync.test.subject.c 继承的 sync.test.subject.b 有许多很多关系 .

通过名为 _compute_separated_chars 的计算函数填充 sync.test.subject.b 的 split_chars 字段 , 该函数由 sync.test.subject.b 的 chars 字段的更改触发 .

sync.test.subject.c 的作用基本上是通过自己的名称设置字符 , 以便触发 _compute_separated_chars.

这样做会触发 " 错误 ":

> 创建一个新的 sync.test.subject.c 输入任何名称 , 例如 ABCDEFG

> 保存新的 sync.test.subject.c

> 通过按将名称设置为字符按钮来调用 action_set_char

您将看到该函数被触发两次 .

这是执行的结果:

CHAR SEPARATION BEGINSEPARATE CHARSDELETE CURRENT CHARSDELETE EXISTING sync_test_subject_a THAT ARE RELATED TO CURRENT SELFINSERT NEW CHAR RECORDSUPDATE self.separated_chars WITH CHAR IDSCHAR SEPARATION BEGINSEPARATE CHARSDELETE CURRENT CHARSDELETE EXISTING sync_test_subject_a THAT ARE RELATED TO CURRENT SELFINSERT NEW CHAR RECORDSUPDATE self.separated_chars WITH CHAR IDSCHAR SEPARATION ENDCHAR SEPARATION END

结果 , 仅应为 A,B,C,D,E,F,G 的记录翻倍为 A,B,C,D,E,F,G,A,B,C,D,E, F,G 这是非常危险的行为 , 因为这可能导致数据崩溃 .

这是一个详细的逐步布局 ( 基于打印结果 ) :

M1 = first call to the methodM2 = second call to the methodFor example in this casechars = ABCDEFG > trigger the methodM1 - CHAR SEPARATION BEGINM1 - SEPARATE CHARS M1 tries to separate the chars into list [ A,B,C,D,E,F,G ] M1 - DELETE CURRENT CHARS This is needed to REPLACE current character records with the new ones. since the `separated_chars` is currently empty nothing will be deletedM1 - DELETE EXISTING sync_test_subject_a THAT ARE RELATED TO CURRENT SELF The method will try to get all of the `sync.test.subject.a` ids that is related to self by getting them from `separated_chars` so that they can be unlinked ( This happens before M1 - DELETE CURRENT CHARS ) . Since nothing has been added to the `separated_chars`, this will not do anythingM1 - INSERT NEW CHAR RECORDS Adding [ A,B,C,D,E,F,G ] `to sync.test.subject.a`, so `sync.test.subject.a` will have [ A,B,C,D,E,F,G ] M1 - UPDATE self.separated_chars WITH CHAR IDS CURRENTLY THIS IS NOT YET EXECUTED, so no `sync.test.subject.a` ids has been assigned to self. it will wait till M2 finish executing.M2 - CHAR SEPARATION BEGINM2 - SEPARATE CHARS M1 tries to separate the chars into list [ A,B,C,D,E,F,G ] M2 - DELETE CURRENT CHARS Because the `separated_chars` IS STILL EMPTY nothing happens.M2 - DELETE EXISTING sync_test_subject_a THAT ARE RELATED TO CURRENT SELF See, currently the `separated_chars` field IS STILL EMPTY THOUGH the `sync.test.subject.a` is filled with [ A,B,C,D,E,F,G ] the method can't get the ids because the `separated_chars` is empty.M2 - INSERT NEW CHAR RECORDS Now the method adds [ A,B,C,D,E,F,G ] `to sync.test.subject.a`, so `sync.test.subject.a` will have [ A,B,C,D,E,F,G,A,B,C,D,E,F,G ] M2 - UPDATE self.separated_chars WITH CHAR IDS This will link `sync.test.subject.a` ids to self so now self has [ A,B,C,D,E,F,G ] M2 - CHAR SEPARATION END Now after this M1 will continue linking the `sync.test.subject.a` ids to self that means self will now have [ A,B,C,D,E,F,G,A,B,C,D,E,F,G ] M1 - CHAR SEPARATION ENDSee the problem isn't how many times the method is executed but it's how the method calls itself when it tries to update the field. Which is nonsense.

问题:

> 为什么 _compute_separated_chars 在位置被两次调用

同一时刻?

> 假定 _compute_separated_chars 的触发器

是对 chars 的更新 , 而 chars 仅更新一次 , 为什么

该方法被调用两次吗?

源文件:Source

我认为您的问题出在其他地方 . 没关系 ,Odoo 会调用您的 _compute_separated_chars 方法多少次 , 而您必须正确返回 septed_chars 字段的值 . 我的问题在哪里呢?

split_chars 字段的值是在 _compute_separated_chars 方法内部计算的 . 因此 , 在调用此方法时 , 此字段的值是不确定的!您不能依靠它 . 但是您可以 - 使用此值删除现有记录 .

如果进一步调试 , 您将看到执行该方法时 ,septed_chars 的值可能为空 . 这样 , 您什么也不会删除 . 如果您对数据库表 sync_test_subject_a 中的行数进行计数 , 您可能会发现随着 _compute …方法的每次执行 , 行数都在增加 .

尝试为您的多对多字段计算阐述一些不同的逻辑 .

此后 , 我将为您提供一种更清洁的方法 , 但是您的问题仍然存在 . 由于未在调用时 self.separated_chars 为空 , 所以未断开 split_chars 的链接!

@api.one@api.depends ( 'chars' ) def _compute_separated_chars ( self ) : a_model = self.env [ 'sync.test.subject.a' ] if not self.chars: return self.separated_chars.unlink ( ) for character in self.chars: self.separated_chars += n a_model.create ( {'name': character} )

以上内容由"CocoaChina"上传发布 查看原文
相关标签 方法此方法

觉得文章不错,微信扫描分享好友

扫码分享