Search 1.9 billion lines of Odoo code on GitHub

demo_abstractmodel_tutorial

Author: My Company
License: no license
Branch: master
Repository: twtrubiks/odoo-demo-addons-tutorial
Dependencies: hr_expense, and web
Languages: Markdown (178, 56.9%), Python (55, 17.6%), and XML (80, 25.6%)
Other branches: 14.0

<h1>介紹 AbstractModel</h1> <p>建議觀看影片, 會更清楚:smile:</p> <p><a href="">Youtube Tutorial - (等待新增)odoo 手把手教學 - AbstractModel</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>主要介紹 demo<em>abstractmodel</em>tutorial</p> <h2>說明</h2> <p><code>AbstractModel</code> AbstractModel = BaseModel,</p> <p>注意:exclamation::exclamation: AbstractModel <strong>不會</strong> 在資料庫中產生對應的 table.</p> <p>AbstractModel 除了常常使用在之前介紹的 <a href="https://github.com/twtrubiks/odoo-demo-addons-tutorial/tree/master/demo_prototype_inheritance">demo<em>prototype</em>inheritance</a> 中,</p> <p>也很常使用在 report 中 (自定義一些額外的邏輯),</p> <p>可參考 odoo code 中的 <code>addons/sale/report/sale_report.py</code>,</p> <p>```python ...... class SaleOrderReportProforma(models.AbstractModel): <em>name = &#39;report.sale.report</em>saleproforma&#39; _description = &#39;Proforma Report&#39;</p> <pre><code>def _get_report_values(self, docids, data=None): docs = self.env[&#39;sale.order&#39;].browse(docids) return { &#39;doc_ids&#39;: docs.ids, &#39;doc_model&#39;: &#39;sale.order&#39;, &#39;docs&#39;: docs, &#39;proforma&#39;: True } </code></pre> <p>```</p> <p>假如你的 report 有額外的邏輯, 可以將邏輯寫在 <code>_get_report_values</code> 中.</p> <p>請一定要先了解 Transient Model, 如果不了解可參考 <a href="https://github.com/twtrubiks/odoo-demo-addons-tutorial/tree/master/demo_odoo_tutorial_wizard">demo<em>odoo</em>tutorial_wizard</a>.</p> <p>開始今天的介紹:smile:</p> <p>先來看 <a href="wizard/model_wizard.py">wizard/model_wizard.py</a></p> <p>```python class ReportWizard(models.TransientModel): _name = &#39;report.wizard&#39; _description = &quot;Report Wizard&quot;</p> <pre><code>date_start = fields.Date(string=&quot;Start Date&quot;, required=True, default=fields.Date.today) date_end = fields.Date(string=&quot;End Date&quot;, required=True, default=fields.Date.today) @api.multi def download_report(self): _logger.warning(&#39;=== CALL get_report ===&#39;) data = { &#39;ids&#39;: self.ids, &#39;model&#39;: self._name, &#39;form&#39;: { &#39;date_start&#39;: self.date_start, &#39;date_end&#39;: self.date_end, }, } return self.env.ref(&#39;demo_abstractmodel_tutorial.action_report_abstractmodel&#39;).report_action(self, data=data) </code></pre> <p>...... ```</p> <p>頁面上會有一個按鈕觸發 <code>download_report</code>,</p> <p><code>demo_abstractmodel_tutorial.action_report_abstractmodel</code> 為</p> <p>addons name + report id (report id 後面會說明) <code>addons_name.report_id</code></p> <p><code>report_action()</code> 會去 call <code>_get_report_values()</code>.</p> <p><a href="wizard/model_wizard.xml">wizard/model_wizard.xml</a></p> <p>```xml &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt; <odoo> <record model="ir.ui.view" id="custom_report_wizard"> <field name="name">Custom Report</field> <field name="model">report.wizard</field> <field name="type">form</field> <field name="arch" type="xml"> <form string="Custom Report"> <group> <group> <field name="date_start"/> </group> <group> <field name="date_end"/> </group> </group> <footer> <button name="download_report" string="Download Report" type="object" class="oe_highlight"/> <button string="Cancel" special="cancel"/> </footer> </form> </field> </record></p> <pre><code>&lt;act_window id=&quot;action_custom_report_wizard&quot; name=&quot;Action Custom Report&quot; res_model=&quot;report.wizard&quot; view_mode=&quot;form&quot; target=&quot;new&quot;/&gt; &lt;menuitem action=&quot;action_custom_report_wizard&quot; id=&quot;menu_custom_report_wizard&quot; parent=&quot;hr_expense.menu_hr_expense_reports&quot;/&gt; </code></pre> <p></odoo> ```</p> <p>這邊定義了基本的 form, 並且將 menu 設定在 <code>hr_expense.menu_hr_expense_reports</code> 之下.</p> <p><img src="https://i.imgur.com/BL4en9D.png" alt="alt tag"></p> <p><img src="https://i.imgur.com/VnuJXrI.png" alt="alt tag"></p> <p>剛剛前面提到 report id <code>action_report_abstractmodel</code> 在 <a href="reports/report.xml">reports/report.xml</a></p> <p>```xml &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt; <odoo> <template id="report_wizard_template"> <t t-call="web.html_container"> <div class="header"> <h3 class="text-center">Expense Wizard Report</h3> <h4 class="text-center"> <strong>From</strong>: <t t-esc="date_start"/> <strong>To</strong>: <t t-esc="date_end"/> </h4> </div> <div> <table> <thead> <th class="text-center">Name</th> <th class="text-center">Date</th> <th class="text-center">Unit<em>amount</th> </thead> <tbody> <t t-foreach="docs" t-as="doc"> <tr> <td> <span t-esc="doc['name']"/> </td> <td class="text-center"> <span t-esc="doc['date']"/> </td> <td class="text-center"> &lt;span t-esc=&quot;doc[&#39;unit</em>amount&#39;]&quot;/&gt; </td> </tr> </t> </tbody> </table> </div> </t> </template></p> <pre><code>&lt;report id=&quot;action_report_abstractmodel&quot; string=&quot;Demo Report&quot; model=&quot;report.wizard&quot; report_type=&quot;qweb-pdf&quot; name=&quot;demo_abstractmodel_tutorial.report_wizard_template&quot; print_report_name=&quot;Demo Report&quot; /&gt; </code></pre> <p></odoo> ```</p> <p>分別設定了 template id <code>report_wizard_template</code> 以及 report id <code>action_report_abstractmodel</code>.</p> <p><code>name</code> 的部份為 adddons name + template id.</p> <p>也就是 <code>adddons_name.template_id</code>.</p> <p>接著看 <a href="wizard/model_wizard.py">wizard/model_wizard.py</a> 的後半段,</p> <p>```python ...... class ReportExpenseAbstractModel(models.AbstractModel): <em>name = &#39;report.demo</em>abstractmodel<em>tutorial.report</em>wizard_template&#39; _description = &#39;Report Expense Wizard&#39;</p> <pre><code>@api.model def _get_report_values(self, docids, data=None): _logger.warning(&#39;=== CALL get_report_values ===&#39;) date_start = data[&#39;form&#39;][&#39;date_start&#39;] date_end = data[&#39;form&#39;][&#39;date_end&#39;] docs = self.env[&#39;hr.expense&#39;].search([ (&#39;date&#39;, &#39;&gt;=&#39;, date_start), (&#39;date&#39;, &#39;&lt;=&#39;, date_end)], order=&#39;date asc&#39;) return { &#39;doc_ids&#39;: data[&#39;ids&#39;], &#39;doc_model&#39;: data[&#39;model&#39;], &#39;date_start&#39;: date_start, &#39;date_end&#39;: date_end, &#39;docs&#39;: docs, } </code></pre> <p>```</p> <p>前面說過了 <code>report_action()</code> 會去 call <code>_get_report_values()</code>,</p> <p>所以這邊定義了 <code>AbstractModel</code> 並且實作 <code>_get_report_values</code>.</p> <p><code>_name</code> 這邊的比較特別, 要注意一下, 它的結構是由以下幾部份組成,</p> <p>report + addons name + template id</p> <p><code>report.addons_name.template_id</code></p> <p>也就是 <code>report.demo_abstractmodel_tutorial.report_wizard_template</code>,</p> <p>report 這個 prefix 很重要, 請不要任意的拿掉:exclamation::exclamation:</p> <p><code>_get_report_values</code> 則是我們額外的邏輯, 最後將資料回傳給</p> <p><code>report_wizard_template</code> 並且 render.</p> <p><img src="https://i.imgur.com/XqmRovl.png" alt="alt tag"></p>