Search 1.9 billion lines of Odoo code on GitHub

demo_odoo_tutorial_wizard

Author: My Company
License: no license
Branch: 14.0
Repository: twtrubiks/odoo-demo-addons-tutorial
Dependencies: base
Languages: Markdown (175, 50.3%), Python (62, 17.8%), and XML (111, 31.9%)
Other branches: master

<h1>odoo 觀念 - TransientModel - Wizard</h1> <p>建議觀看影片, 會更清楚:smile:</p> <p><a href="https://youtu.be/Gc-wRnAhbKs">Youtube Tutorial - odoo 觀念 - TransientModel - Wizard</a></p> <p>建議在閱讀這篇文章之前, 請先確保了解看過以下的文章 (因為都有連貫的關係)</p> <p><a href="https://github.com/twtrubiks/odoo-demo-addons-tutorial/tree/master/demo_odoo_tutorial">odoo 手把手建立第一個 addons</a></p> <p>本篇文章主要介紹 odoo 中的 wizard 這部份</p> <h2>說明</h2> <p>在 odoo 中, wizard 是一個很特別的 model, 之前除了介紹過最基本的 BaseModel (可參考 <a href="https://github.com/twtrubiks/odoo-demo-addons-tutorial/tree/master/demo_odoo_tutorial">demo<em>odoo</em>tutorial</a>) 之外,</p> <p>今天要來介紹另一個 model, 也就是 TransientModel,</p> <p><code>TransientModel</code> 繼承自 Model, <code>_transient = True</code>,</p> <p>先簡單看一下它的定義,</p> <p>```python class TransientModel(Model): &quot;&quot;&quot; Model super-class for transient records, meant to be temporarily persisted, and regularly vacuum-cleaned.</p> <pre><code>A TransientModel has a simplified access rights management, all users can create new records, and may only access the records they created. The super- user has unrestricted access to all TransientModel records. &quot;&quot;&quot; _auto = True # automatically create database backend _register = False # not visible in ORM registry, meant to be python-inherited only _abstract = False # not abstract _transient = True # transient </code></pre> <p>```</p> <p>TransientModel 是一種特殊的 model, TransientModel 所產生的 model 會在一個時間定期被刪除,</p> <p>所以 TransientModel 只適合建立暫時的數據, 也就是接著要介紹的 wizard.</p> <p>先來看 <a href="wizard/model_wizard.py">wizard/model_wizard.py</a></p> <p>```python class DemoWizard(models.TransientModel): _name = &quot;demo.wizard&quot; _description = &quot;Demo Wizard&quot;</p> <pre><code>wizard_partner_id = fields.Many2one(&#39;res.partner&#39;, string=&#39;Partner&#39;) wizard_test_context = fields.Char(&#39;wizard_test_context&#39;) @api.model def default_get(self, fields): res = super(DemoWizard, self).default_get(fields) default_partner_id = self.env.context.get(&#39;default_partner_id&#39;, []) res.update({ &#39;wizard_partner_id&#39;: default_partner_id, }) # or # res[&#39;wizard_partner_id&#39;] = default_partner_id return res def btn_validate(self): self.ensure_one() context = dict(self._context or {}) default_test_pass_data = context.get(&#39;default_test_pass_data&#39;, []) _logger.warning(&#39;============= btn_validate ==================&#39;) _logger.warning(&#39;default_test_pass_data: %s&#39;, default_test_pass_data) _logger.warning(&#39;wizard_test_context: %s&#39;, self.wizard_test_context) return {&#39;type&#39;: &#39;ir.actions.act_window_close&#39;} </code></pre> <p>```</p> <p>注意:exclamation: 這邊是使用 <code>models.TransientModel</code>.</p> <p>注意:exclamation: 從 odoo14 開始, Transient models <strong>需要</strong> access rules.</p> <p>可參考 <a href="https://github.com/twtrubiks/odoo-demo-addons-tutorial/blob/14.0/demo_odoo_tutorial_wizard/security/ir.model.access.csv">security/ir.model.access.csv</a> 中的設定.</p> <p><a href="views/view.xml">views/view.xml</a></p> <p>```xml ......</p> <p><record id="view_form_demo_odoo_tutorial" model="ir.ui.view"> <field name="name">Demo Odoo Tutorial Form</field> <field name="model">demo.odoo.wizard.tutorial</field> <field name="arch" type="xml"> <form string="Demo Odoo Tutorial"> <header> <button name="%(demo_odoo_tutorial_wizard.demo_wizard_action)d" type="action" string="Call Wizard" class="oe_highlight" context="{'default_partner_id': partner_id}"/> </header> <sheet> <group> <field name="name"/> <field name="partner_id"/> </group> </sheet> </form> </field> </record> ...... ```</p> <p>重點在 button 這段, 這段是去呼叫 <code>demo_wizard_action</code>,</p> <p>寫法是 <code>name=&quot;%(demo_odoo_tutorial_wizard.demo_wizard_action)d&quot;</code>,</p> <p>路徑在 <a href="wizard/model_wizard.xml">wizard/model_wizard.xml</a></p> <p>```xml ...... <record id="demo_wizard_view_form" model="ir.ui.view"> <field name="name">demo.wizard.form</field> <field name="model">demo.wizard</field> <field name="arch" type="xml"> <form string="Wizard Form"> <sheet> <div class="oe_title"> <h1>Wizard Title</h1> </div> <group> <field name="wizard_partner_id"/> <field name="wizard_test_context"/> </group> </sheet> <footer> <button string='Validate' name="btn_validate" type="object" class="btn-primary"/> <button string="Cancel" class="btn-secondary" special="cancel"/> </footer> </form> </field> </record></p> <pre><code>&lt;!-- demo_wizard_action --&gt; &lt;record id=&quot;demo_wizard_action&quot; model=&quot;ir.actions.act_window&quot;&gt; &lt;field name=&quot;name&quot;&gt;Demo Wizard Action&lt;/field&gt; &lt;field name=&quot;res_model&quot;&gt;demo.wizard&lt;/field&gt; &lt;field name=&quot;view_type&quot;&gt;form&lt;/field&gt; &lt;field name=&quot;view_mode&quot;&gt;form&lt;/field&gt; &lt;field name=&quot;view_id&quot; ref=&quot;demo_wizard_view_form&quot;/&gt; &lt;field name=&quot;target&quot;&gt;new&lt;/field&gt; &lt;field name=&quot;context&quot;&gt;{&#39;default_test_pass_data&#39;: &#39;hello 123&#39;}&lt;/field&gt; &lt;/record&gt; </code></pre> <p>......</p> <p>```</p> <p>點選 Call Wizard,</p> <p><img src="https://i.imgur.com/CXK9ePn.png" alt="alt tag"></p> <p>會跳出 Wizard,</p> <p><img src="https://i.imgur.com/aIOT2mI.png" alt="alt tag"></p> <p>Partner 會幫你自動帶入 partner_id,</p> <p>原因是因為使用了 context <code>{&#39;default_partner_id&#39;: partner_id</code>,</p> <p>以及 <code>def default_get(self, fields)</code> 的方法實現.</p> <p>當你在 <code>wizard_test_context</code> 輸入任何內容 (twtrubiks), 然後點選 Validate</p> <p><img src="https://i.imgur.com/2WWQQCj.png" alt="alt tag"></p> <p>它會 call <code>def btn_validate</code>,</p> <p>然後從 CLI 你會看到兩條 log,</p> <p><img src="https://i.imgur.com/nZDDTmp.png" alt="alt tag"></p> <p>log 1, <code>default_test_pass_data: hello 123</code></p> <p>會出現這條訊息的原因是因為設定了預設的 context,</p> <p><code>&lt;field name=&quot;context&quot;&gt;{&#39;default_test_pass_data&#39;: &#39;hello 123&#39;}&lt;/field&gt;</code></p> <p>log 2, <code>wizard_test_context: twtrubiks</code></p> <p>這條訊息則是顯示剛剛輸入的內容.</p> <p>另一種傳值的方式, 也可以全部透過 python 來完成,</p> <p>可參考 <a href="models/models.py">models/models.py</a></p> <p>```python ...... @api.multi def action<em>context</em>demo(self): # if self.<em>context.get(&#39;context</em>data&#39;, False): if self.env.context.get(&#39;context_data&#39;): raise ValidationError(&#39;have context data&#39;) raise ValidationError(&#39;hello&#39;)</p> <p>@api.multi def action<em>button(self): for record in self: record.with</em>context(context<em>data=True).action</em>context_demo() ...... ```</p> <p><a href="views/view.xml">views/view.xml</a> 的部份,</p> <p>```xml ...... <button name="action_context_demo" type="object" string="action context demo" class="oe_highlight"/></p> <p><button name="action_button" type="object" string="action button" class="oe_highlight"/> ...... ```</p> <p><img src="https://i.imgur.com/oqnr1Ox.png" alt="alt tag"></p> <p>當點下 <code>action context demo</code> button 時,</p> <p>會跳出 hello, 因為 <code>context_data</code> 為 <code>False</code>.</p> <p><img src="https://i.imgur.com/6rMlJHK.png" alt="alt tag"></p> <p>當點下 <code>action button</code> button 時,</p> <p>會跳出 have context data, 因為 <code>context_data</code> 為 <code>True</code>,</p> <p>主要透過 <code>record.with_context(context_data=True).action_context_demo()</code> 這段,</p> <p>將 <code>context_data</code> 送進去.</p> <p><img src="https://i.imgur.com/YIoy0yL.png" alt="alt tag"></p>