计算方法被多次调用? [英] Compute method is called multiple times?

查看:72
本文介绍了计算方法被多次调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现这可能不是并发问题,因为 只需在尝试更新sync.test.subject.bseparated_chars字段时调用该方法(在方法末尾).所以 我无法使用线程锁定解决此问题,因为该方法实际上等待再次调用自身.我不明白这是一种完全奇怪的行为.

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.

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

I found a weird behavior while updating computed fields. In this case codes are better than words:

型号:

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.name

sync_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.async.test.subject.b有很多很多的关系,而sync.test.subject.bsync.test.subject.c继承.

There are 3 classes, sync.test.subject.a which has many2many relation with sync.test.subject.b which is inherited by sync.test.subject.c.

sync.test.subject.bseparated_chars字段通过称为_compute_separated_chars的计算函数填充,该函数由sync.test.subject.bchars字段的更改触发.

sync.test.subject.b's separated_chars field is populated through a compute function called _compute_separated_chars which is triggered by the change of sync.test.subject.b's chars field.

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

The role of sync.test.subject.c is basically to set chars by its own name so that _compute_separated_chars is triggered.

"bug"是通过执行以下操作触发的:

The "bug" is triggered by doing this:

  • 创建一个新的sync.test.subject.c输入任何名称,例如ABCDEFG
  • 保存新的sync.test.subject.c
  • 按下Set Name To Chars按钮呼叫action_set_char
  • Create a new sync.test.subject.c input whatever name for example ABCDEFG
  • Save the new sync.test.subject.c
  • Call action_set_char by pressing the Set Name To Chars button

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

You will see that the function is triggered twice.

这是执行的结果:

CHAR SEPARATION BEGIN
SEPARATE CHARS
DELETE CURRENT CHARS
DELETE EXISTING sync_test_subject_a THAT ARE RELATED TO CURRENT SELF
INSERT NEW CHAR RECORDS
UPDATE self.separated_chars WITH CHAR IDS
CHAR SEPARATION BEGIN
SEPARATE CHARS
DELETE CURRENT CHARS
DELETE EXISTING sync_test_subject_a THAT ARE RELATED TO CURRENT SELF
INSERT NEW CHAR RECORDS
UPDATE self.separated_chars WITH CHAR IDS
CHAR SEPARATION END
CHAR SEPARATION END

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

As the result the records which are only supposed to be A,B,C,D,E,F,G doubled into A,B,C,D,E,F,G,A,B,C,D,E,F,G. This is a really dangerous behavior because this can cause data crashes.

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

This is a detailed step by step layout on how this happens (based on the printout):

M1 = first call to the method
M2 = second call to the method

For example in this case

chars = ABCDEFG > trigger the method

M1 - CHAR SEPARATION BEGIN
M1 - 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 deleted

M1 - 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 anything

M1 - 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 BEGIN
M2 - 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 END

See 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 同一时刻?
  • 假定为_compute_separated_chars的触发器 是对chars的更新,而chars仅更新一次,为什么 方法被调用两次了吗?
  • Why is the _compute_separated_chars called twice at the same moment?
  • The trigger for _compute_separated_chars is supposed to be an update to chars and the chars is only updated ONCE, why is the method called twice?

源文件:

推荐答案

我认为您的问题出在其他地方.没关系,Odoo调用您的_compute_separated_chars方法需要多少次才能正确返回separated_chars字段的值.对我来说哪里出问题了?

I think that your problem is elsewhere. Never mind how many time Odoo invokes your _compute_separated_chars method you have to return correctly the value of the separated_chars field. And where is the problem for me?

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

The value of the separated_chars field is calculated inside your _compute_separated_chars method. So, in the time of invocation of this method the value of this field is undefined! You cannot rely on it. But you do - you use this value for deleting the existing records.

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

If you debug furthermore you'll see that when the method is executed, the value of separated_chars is probably empty. In this way you delete nothing. If you count the number of rows in your database table sync_test_subject_a you'll probably see that they are increasing with every execution of your _compute... method.

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

Try to elaborate a little bit different logic for your many2many relation field computation.

此后,我将为您提供方法的更干净版本,但是您的问题仍然存在.由于在调用self.separated_chars时为空!

I'm giving you hereafter a cleaner version of your method but your problem still exists. The separated_chars are not unlinked because in the time of invocation self.separated_chars in empty!

@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 += \
                a_model.create({'name': character})

这篇关于计算方法被多次调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆