2015-09-14 2 views
8

に継承されているsync.test.subject.bと多くの2つの関係を持つsync.test.subject.aの3つのクラスがあります。他のフィールドや他のモデルを計算機能の内部から更新するにはどうすればよいですか?

sync.test.subject.b S charsフィールドのseparated_charsフィールドはsync.test.subject.bの変化によってトリガされる_compute_separated_charsと呼ばれる計算関数を介して取り込まれます」。

sync.test.subject.cの役割は、基本的にcharsnameに設定して、_compute_separated_charsをトリガーします。

問題は、関数が実行される前にフィールドが既にシステムによって空になっているため、計算関数内からMany2manyフィールド(つまり、sync.test.subject.a残存レコード)に関連する残存レコードを削除できないため、 idsを取得する。 separated_charsに関連していない変更は、計算機能の中からシステムによってコミットされないため、sync.test.subject.aのIDを格納するための一時フィールドを使用することはできません(変更によって、実際には同じモデルまたは他のモデルへの他の変更はコミットされません)。これをどうすれば解決できますか?

モデル:

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.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() 
     #DELETE LEFTOVER RECORDS FROM a_model 
     for character in self.chars: 
      self.separated_chars += a_model.create({'name': character}) 

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> 

私はこの動作はチェーン計算フィールドを扱うためのOdooによって怠惰な実装に起因していると思う順に基づいて、(正しくトリガを処理するのではなく、トリガー依存関係)彼らはただ更新すべての計算フィールドEVERYTIMEは、他のすべてのフィールドに変更があります。そしてそのために、compute関数の中から他のフィールドへの更新を制限します。なぜなら、そうでなければ、再帰的な計算関数呼び出しで爆発するからです。

答えて

5

質問は興味深いので、新しいOdoo APIの動作については、computeメソッドで少し再生する時間がかかりました。いくつかの時期尚早な陳述がありますが、あなたの質問で言うことは全く間違っているわけではありません。

Odooの動作を実証するために、次のデザインの簡単な書籍アプリケーションを作成しました。

「books.book」と「books.author」の2つのモデルがあります。それぞれの書籍は1人または複数の著者によって書かれ、すべての著者は1つまたは複数の書籍を書かれているはずであるので、通常のモードよりもモードが普通です。

Many2many関連のオブジェクトをこのようなcomputeメソッドから処理するために、ちょっとした工夫をしています。これは、Many2manyレコードが存在し、それぞれのレコードが互いに独立しているためです。 One2manyとの関係は大きく異なります。あなたは私たちを見るの挙動を再現する

しかし、どのような方法は、あなたの例では、私はを計算author.booksフィールドを作った - それは価値が_get_books()方法ああauthorクラスによって計算されています。nameauthorクラスのメソッド_get_full_name()ことが計算されます - ただ、別の計算フィールドは、私は別の計算結果フィールドを作成し、十分かつ独立して動作することを示すために

ここで_get_books()メソッドについてのいくつかの言葉。 books_listテキストフィールドに基づいて、このメソッドはbooks_listの1行につき1つのブックを生成します。

本を作成する際には、この名前の本がすでに存在するかどうかを最初に確認します。この場合、この本は著者にリンクしています。それ以外の場合は、新しい本が作成され、著者にリンクされます。

そして今、あなたが興味を持っている質問 - 新しい本の作成に先立ち、この著者に関する既存の本はが削除されましたです。これを行うには、ローレベルSQLクエリを使用します。このようにして、computeメソッド内に関連するオブジェクトのリストがないという問題に対処します。別のフィールドから次さに依存計算フィールドを扱うときあなたの心に持っている必要がありますどのような

  • 彼らが依存フィールドは(良いニュースthatsの)変更されたとき、彼らが計算されている
  • それらを再計算する必要性は、その価値にアクセスしようとするたびに評価されます。したがって、無限の再帰を避けるためにいくつかの注意が必要です。

computeメソッド内の別のフィールドの値の変更について。メソッドのonchange注

だけクライアントに を送信するためにどの値を知るために使用 がデータベースに書き込まれていないこれらのレコード上の仮想記録の割り当て、上で動作:documentationの以下の部分を読みます

computeも有効です。それはどういう意味ですか?つまり、モデルの別のフィールドに値を割り当てると、この値はデータベースに書き込まれません。しかし、値はユーザーインターフェイスに返され、フォームを保存しながらデータベースに書き込まれます。

サンプルコードを貼り付ける前に、アプリケーションのデザインを変更し、computeメソッドの中のmany2manyリレーションでこのように扱わないことを再度お勧めします。新しいオブジェクトの作成はうまくいくが、既存のオブジェクトの削除や変更はやりにくく、楽しいものではない。あなたは、たとえば、著者のクラスをサブクラス化する場合よりも、

<openerp> 
    <data> 
     <menuitem id="books" name="Books App" sequence="0" /> 
     <menuitem id="books.library" name="Library" 
      parent="books" sequence="0" /> 
     <record model="ir.ui.view" id="books.book_form"> 
      <field name="name">books.book.form</field> 
      <field name="model">books.book</field> 
      <field name="type">form</field> 
      <field name="arch" type="xml"> 
       <group col="2"> 
        <field name="name" /> 
       </group> 
       <field name="authors" string="Authors" /> 
      </field> 
     </record> 
     <record model="ir.ui.view" id="books.book_tree"> 
      <field name="name">books.book.tree</field> 
      <field name="model">books.book</field> 
      <field name="type">tree</field> 
      <field name="arch" type="xml"> 
       <field name="name" /> 
       <field name="authors" string="Authors" /> 
      </field> 
     </record> 
     <record id="books.book_action" model="ir.actions.act_window"> 
      <field name="name">Books</field> 
      <field name="res_model">books.book</field> 
      <field name="type">ir.actions.act_window</field> 
      <field name="view_type">form</field> 
      <field name="view_mode">tree,form</field> 
     </record> 
     <menuitem id="books.books_menu" name="Books" 
      parent="books.library" sequence="10" 
      action="books.book_action"/> 
     <record model="ir.ui.view" id="books.author_tree"> 
      <field name="name">books.author.tree</field> 
      <field name="model">books.author</field> 
      <field name="type">tree</field> 
      <field name="arch" type="xml"> 
       <field name="name" /> 
       <field name="books_list" /> 
       <field name="notes" /> 
       <field name="books" string="Books" /> 
      </field> 
     </record> 

     <record model="ir.ui.view" id="books.author_form"> 
      <field name="name">books.author.form</field> 
      <field name="model">books.author</field> 
      <field name="type">form</field> 
      <field name="arch" type="xml"> 
       <field name="name" /> 
       <group col="4"> 
        <field name="first_name" /> 
        <field name="second_name" /> 
       </group> 
       <group col="6"> 
        <field name="books_list" /> 
        <field name="notes" string="Notes"/> 
        <field name="books" string="Books" /> 
       </group> 
      </field> 
     </record> 
     <record id="books.author_action" model="ir.actions.act_window"> 
      <field name="name">Authors</field> 
      <field name="res_model">books.author</field> 
      <field name="type">ir.actions.act_window</field> 
      <field name="view_type">form</field> 
      <field name="view_mode">tree,form</field> 
     </record> 
     <menuitem id="books.authors" name="Authors" 
      parent="books.library" sequence="5" 
      action="books.author_action"/> 
    </data> 

EDIT

from openerp import models, fields, api 


class book(models.Model): 

    _name = 'books.book' 
    _description = 'Some book' 
    name = fields.Char('Name') 
    authors = fields.Many2many('books.author', string='Author', 
           relation='books_to_authors_relation', 
           column1='book_id', column2='author_id') 

book() 


class author(models.Model): 

    _name = 'books.author' 
    _description = 'Author' 
    first_name = fields.Char('First Name') 
    second_name = fields.Char('Second Name') 
    name = fields.Char('Name', compute='_get_full_name', store=True) 
    books_list = fields.Text('List of books') 
    notes = fields.Text('Notes') 
    books = fields.Many2many('books.book', string='Books', 
          relation='books_to_authors_relation', 
          column1='author_id', column2='book_id', 
          compute='_get_books', store=True) 

    @api.one 
    @api.depends('first_name', 'second_name') 
    def _get_full_name(self): 
     import pdb; pdb.set_trace() 
     if not self.first_name or not self.second_name: 
      return 
     self.name = self.first_name + ' ' + self.second_name 

    @api.depends('books_list') 
    def _get_books(self): 
     if not self.books_list: 
      return 

     books = self.books_list.split('\n') 

     # Update another field of this object 
     # Please note that in this step we update just the 
     # fiedl in the web form. The real field of the object 
     # will be updated when saving the form 
     self.notes = self.books_list 

     # Empty the many2many relation 
     self.books = None 

     # And delete the related records 
     if isinstance(self.id, int): 
      sql = """ 
       DELETE FROM books_to_authors_relation 
        WHERE author_id = %s 
      """ 
      self.env.cr.execute(sql, (self.id,)) 
      sql = """ 
       DELETE FROM books_book 
        WHERE 
         name not in %s 
        AND id NOT in (
         SELECT id from books_book as book 
          INNER JOIN books_to_authors_relation 
           as relation 
           ON book.id = relation.book_id 
           WHERE relation.author_id != %s) 
      """ 
      self.env.cr.execute(sql, (tuple(books), self.id,)) 
      ### As per the documentation, we have to invalidate the caches after 
      ### low level sql changes to the database 
      ##self.env.invalidate_all() 
     # Create book records dinamically according to 
     # the Text field content 
     book_repository = self.env['books.book'] 
     for book_name in books: 
      book = book_repository.search([('name', '=', book_name)]) 
      if book: 
       self.books += book 
      else: 
       self.books += book_repository.create({'name': book_name, }) 
     return 

author() 

とユーザーインターフェイス:ここ

books.pyファイルですrelation、を削除しますMany2manyフィールド定義のおよびcolumn2属性。彼はデフォルトの関係テーブル名を残します。

def _get_relation_table(self): 
    return 'books_author_books_book_rel' 

、あなたは、この関係テーブルからレコードを削除したいときに、SQLクエリの構築では、このメソッドを使用します。

今、あなたは、このようなメソッドをサブクラスごとに定義することができます。

+0

Andrei、あなたは男です!ハハ。私は低レベルのSQLクエリを使用することは考えていません。 Many2many関係を使用する理由は、この問題のためです。http://stackoverflow.com/questions/29962101/is-it-possible-to-make-a-one2many-relation-without-specifying-the-target-models 。 Odooの継承はJavaの継承とは異なり、サブクラスによって継承されるone2manyフィールドを持つスーパークラスをどのように記述するのか分かりません。したがって、私はこの問題に遭遇するまで、うまくいく、多くの多くの関係を代わりに使うことに決めました。 – William

+0

しかし、スーパークラスを拡張するたびに*関係テーブルが変わるので、あなたのソリューションを変更する必要があります*! – William

+0

他の問題は完全に別のところです:)私はもう一つの質問に答えます。 Odooの継承では、委譲によってです - Pythonクラスの継承を使用しないで、代わりにOdoo _inherit = '....'を使用してください。 –