Reprint: http://book.odoomommy.com/chapter2/README2.html
Chapter II action
Actions in odoo refer to a series of click operations corresponding to different application scenarios. The most common is act_ The window action, such as opening the form view, tree view and search view, is act_window action. The actions in odoo can be divided into the following categories:
- act_window: work related to the view, such as form\tree\search\kanban, etc.
- act_window_close: and act_widnow is used together to close the window.
- act_url: page Jump related actions
- Server: trigger server action
- todo: Configuration Wizard
- Client: client related actions
General properties
The action types listed above are inherited from IR actions. Actions object, all of which have several important properties in common:
- Name: action name
- Type: action type, usually type name
- xml_id: referenced external xml_id
- help: description
- binding_model_id: displays the model of the menu item in the Sidebar (binding model)
- binding_type: binding type. The optional values are action and action_form_only and report, the default is action, action and action_ form_ The difference between only and action is that action will be a button on the sidebar, which is displayed in the tree and form views_ form_ Only is displayed only in the form. Report is used for report printing.
act_window
View action type, which is one of the most frequently used actions. The views we created in the previous example will be associated to a menu by binding an action, and then will be displayed in the page. When we click the menu, we will trigger the binding action, find the associated view, and finally render the page we see.
Act is described in detail below_ Properties and functions of window:
- view_id: Specifies the page to which the action is bound, and the value is the XML of the page_ id.
- domain: filter condition, the value is python expression, and the target data is filtered.
- context: context
- res_id: the associated database ID, only when the view_ The mode parameter works only when it is a form
- res_model: the model to which the view data to open belongs
- src_model: the source model to which the action is bound (open the action on the model)
- Target: target window. The optional values are current\new\inline\fullscreen\main. The default is current, that is, it opens in the current window. New is a pop-up window, which is our common modal window.
- view_mode: view type, tree,form,kanban, etc
- view_type: the type used to display the list view. The optional values are tree and form.
- usage: filter options for menus and default actions on the user page
- view_ids: associated view object (one2many)
- Views: displayed views
- limit: the number of items displayed in the tree view
- groups_id: group id with access
- search_view_id: associated search view id
- multi: whether the real is only displayed in the tree view.
About IR actions. act_ The use examples of window are not introduced here. Many places in the previous examples are used. I believe you are familiar with this.
However, there is a problem that we should pay attention to, that is, when defining xml, we usually define action first, and then define the menu object. Otherwise, there may be an error and the action cannot be found.
13.0 cancel view_type field
act_window_close
ir. actions. act_ window_ The function of close is very simple. It is to close the current window. A common scenario is when the window needs to be closed after a section of business logic is completed. At this point, you only need to return an act_window_close.
def btn_OK(self): return { 'type':'ir.actions.act_window_close' }
The above code is part of a three-party module of the author. The function of this module is to pop up a window to tell the user the execution result after the execution of a piece of code. When the user clicks the OK button, the pop-up window will be closed automatically. Detailed code can refer to here
act_url
Another important but not very common application scenario in odoo is page Jump or file download. Usually, because the encapsulated many2one and many2any spaces have their own jump connections, we generally don't need to pay too much attention to the page Jump. But when we need to specify a jump page, we need to use IR actions. act_ URL to help us do this.
url has few optional parameters:
- url: the url to jump to
- target: whether to open in a new window or jump to this page (new,self). The default is new
For example, if I want to add a menu and click it to open Bing search, my action can be written as follows:
<record id="act_bing" model="ir.actions.act_url"> <field name="name">open bing Webpage</field> <field name="target">new</field> <field name="url">http://www.bing.com</field> </record>
You should pay attention to the writing of the URL. If you connect to the station connection, you do not need to add the previous host and http protocol header. If you add an external chain, you need to ensure the integrity of the URL.
Another practical scenario is downloading. The principle is the same. We usually put attachments into document management. If I want to download some files (such as templates) in some places, I can add a button for downloading, and the background logic of this button simply returns an act_url:
return { 'type': 'ir.actions.act_url', 'url': f"/web/content/{doc.id}?download=true", 'target': 'new', }
doc.id is the record ID of the attachment searched.
server
The main usage scenario of server type action is to execute a predefined python code. The server type action mainly contains the following attributes:
- sequence: when multiple server action s are to be executed at the same time, they are sorted according to the value of this field.
- model_ ID: which model object does the server script execute on.
- model_ Name: name of model object
- Code: the python code to execute. (including some preset variable types, which will be discussed in subsequent chapters)
- child_ids: list of sub server action s. The result returned by the last sub action is the result returned by the whole action
- crud_model_id: model id to be changed
- crud_model_name: name of the model to be created / changed
- link_field_id: Specifies the field where the current record is many2one associated with the new record
- fields_lines: fields required to create or copy records.
Server action has many uses. The scheduled task in odoo is realized by server action.
Next, we will take exporting sales order Excel file as an example to see how to use server action.
One of the action server applications exports the sales order Excel file
This is a common requirement in the actual implementation process. It is required to export the data of a model to excel. First, we need to organize the data, then use the xlwt library to write an excel file, and finally return the file to the user. Since this action is performed in more buttons, it is more appropriate to define it as a server action.
server action
Define server action
<record id="act_sale_export" model="ir.actions.server"> <field name="name">Sales order export</field> <field name="model_id" ref="sale.model_sale_order"/> <field name="state">code</field> <field name="code"> action=model.export_order() </field> <field name="binding_model_id" ref="sale.model_sale_order"/> </record>
The server action defines the model to be called (sale.order) and the method to be called (export_order). Because we need to return the file to the user through the controller, we need this method to return an action. The method to return the action is to define an action variable to store the return value of the called method. odoo will automatically identify the action and execute the action.
def export_order(self): """Export sales order""" order = self.browse(self.env.context.get("active_id", None)) if order: wkbook = xlwt.Workbook() wksheet = wkbook.add_sheet(f"Sales order{order.name}") wksheet.write(0, 0, "product") wksheet.write(0, 1, "Order quantity") wksheet.write(0, 2, "Unit of measure") wksheet.write(0, 3, "Unit Price") wksheet.write(0, 4, "Subtotal") row = 1 for line in order.order_line: wksheet.write(row, 0, line.product_id.name) wksheet.write(row, 1, line.product_uom_qty) wksheet.write(row, 2, line.product_uom.name) wksheet.write(row, 3, line.price_unit) wksheet.write(row, 4, line.price_subtotal) row += 1 buffer = BytesIO() wkbook.save(buffer) order.export_file = buffer.getvalue() return { 'type': 'ir.actions.act_url', 'url': f"/web/binary/download_document?model=sale.order&field=export_file&id={order.id}&filename={order.name}.xls", 'target': 'self', }
The server action does not bring in the id of the current record when calling. Therefore, we need to manually obtain the record id of the current exported event in the context context, and then write it to the excel file using xlwt. Finally, we return an act_url, which is used to call the download controller defined by us to return the file to the user.
from odoo import http from odoo.http import request from odoo.addons.web.controllers.main import serialize_exception, content_disposition, ensure_db class Binary(http.Controller): @http.route('/web/binary/download_document', type='http', auth="public") @serialize_exception def download_document(self, model, field, id, filename=None, **kw): """ Download link for files stored as binary fields. :param str model: name of the model to fetch the binary from :param str field: binary field :param str id: id of the record from which to fetch the binary :param str filename: field holding the file's name, if any :returns: :class:`werkzeug.wrappers.Response` """ export = request.env[model].sudo().browse(int(id)) filecontent = export.export_file if not filecontent: return request.not_found() else: if not filename: filename = '%s_%s' % (model.replace('.', '_'), id) return request.make_response(filecontent, [('Content-Type', 'application/octet-stream'), ('Content-Disposition', content_disposition(filename))])
This is a general download controller, which is convenient for other types of Excel files to be downloaded in the future. You can call this interface directly. For more information about controller, please refer to the relevant chapters of controller.
todo
ir.actions.todo is defined in IR Actions, but it is indeed a "heterogeneous" of these objects, which does not inherit from IR actions. Actions, that is, IR actions. Todo is not an action. The attribute list of todo is as follows:
- action_id: the id of the action to be executed
- state: status, open or done. The default is open. When the execution is completed, it is set to done
- Sequence: sequence. The default value is 10
- Name: name
Example:
<record id="act_todo" model="ir.actions.todo"> <field name="action_id" ref="act_bing"/> <field name="state">open</field> <field name="sequence">1</field> <field name="type">automatic</field> </record>
There are three optional values for type:
- Manual: manual setting
- Automatic: automatic setting (it is automatically executed every time the system is set, or when the system is installed or upgraded)
- Once: execute only once
The usage scenario of todo is to perform some special actions when installing or upgrading modules.
client
ir. actions. act_ A client action is an action that is completely defined on the client without going through the background. This gives us a way to implement our own pages by bypassing the widget s defined in the background. Client contains the following attributes:
- tag: Specifies the id of the client part
- target: opening method, optional values: current\new\fullscreen\main
- res_model: target model
- params: parameters sent to cleint according to the view tag
- params_store: stored parameters
give an example:
This involves qWeb related content. Students who do not understand qWeb can refer to Chapter 4 and Chapter 5
We first define a menu to bind our client actions:
<record id="act_bing" model="ir.actions.client"> <field name="name">open Bing</field> <field name="tag">web.bing</field> </record> <menuitem name="open Bing" id="book_store.menu_open_bing" action="act_bing" parent="book_store.menu_root"/>
Then we create our own page structure. For simplicity, only one Bing page is embedded here:
<templates xml:space="preserve"> <t t-name="bing"> <iframe marginheight="0" marginwidth="0" width="100%" height="910" src="https://www.bing.com" frameborder="0" allowfullscreen="True"></iframe> </t> </templates>
Then we create our own web widget:
odoo.define('require', function (require) { 'use strict'; var core = require("web.core"); var Widget = require("web.AbstractAction"); var Bing = Widget.extend({ template: "bing", init: function (parent, data) { return this._super.apply(this, arguments); }, start: function () { return true; }, on_attach_callback: function () { } }); core.action_registry.add("web.bing", Bing); return { Bing: Bing }; });
In v11, the Widget needs to be a subassembly of the Widget, and in v12, it needs to be AbstractAction
Finally, we load the defined Bing component into the xml page:
<template id="assets_backend" inherit_id="web.assets_backend"> <xpath expr="script[last()]" position="after"> <script type="text/javascript" src="/book_store/static/src/js/widget.js"/> </xpath> </template>
This completes our customized page, and we can see the effect of upgrading the module:
Here is another example in the enterprise version module. We want to jump to the code scanning module interface on the work order page of the production order. We can use the client actions of the code scanning module:
<record id="stock_barcode_action_main_menu" model="ir.actions.client"> <field name="name">Barcode</field> <field name="tag">stock_barcode_main_menu</field> <field name="target">fullscreen</field> </record>
As you can see, tag can specify not only widget parts, but also directories.
Set default values for actions
Many times, we need to set a default value. For example, when we open a menu, we want to display some grouping or filtering conditions by default according to our requirements, or add default values to some fields. At this time, we can use the context in the action to achieve this purpose.
Set default grouping
When we open a list view, we can use context to display the effect of default grouping:
<record id="project.open_view_project_all" model="ir.actions.act_window"> <field name="type">ir.actions.act_window</field> <field name="view_mode">tree</field> <field name="context">{'group_by':'group_id'}</field> <field name="view_ids" eval="[(6,0,[ref('project_action_view_ref')])]"/> </record>
Group here_ By is the grouping keyword, followed by the field to be grouped.
Set defaults
Suppose we have a list with a button in the list. When we click this button, we want to perform an action and assign a default value to the newly opened page, so we can write as follows:
<!--Redefine tree--> <record id="project_tree_list" model="ir.ui.view"> <field name="name">project</field> <field name="model">project.project</field> <field name="priority">1</field> <field name="arch" type="xml"> <tree> <field name="name"/> <field name="user_id"/> <field name="partner_id"/> <button string="see" class="oe_stat_button" icon="fa-filter" name="%(act_project_to_tasks)d" type="action" context="{ 'default_project_id':active_id }"/> </tree> </field> </record>
active_id represents the id of the current record. The effect is that when we click the button, the project in the new page_ id is given a default value.
Sample code
The following shows how to create a wizard and bind it to the specified model list:
class juhui_repair_top_wizard(models.TransientModel): _name = "juhui.repair.top.wizard" def button_mark_top(self): """Place the repair order on the top""" #[TODO] top pass
First create a temporary model (because the wizard will eventually be destroyed), and then create the corresponding form view:
<record id="juhui_repair_top_wizard_form" model="ir.ui.view"> <field name="name">juhui.repair.top.wizard</field> <field name="model">juhui.repair.top.wizard</field> <field name="arch" type="xml"> <form string="" class=""> <div>Are you sure to top these documents?</div> <footer> <button name="button_mark_top" type="object" string="Top order" class="oe_highlight"/> or <button string="cancel" special="cancel" class="oe_link"/> </footer> </form> </field> </record>
Then there is the configuration action. Different from the normal use, the action here should indicate the bound object.
<record id="action_juhui_repair_top" model="ir.actions.act_window"> <field name="name">Batch top order</field> <field name="type">ir.actions.act_window</field> <field name="res_model">juhui.repair.top.wizard</field> <field name="target">new</field> <field name="view_id" ref="juhui_repair_top_wizard_form"/> <field name="binding_model_id" ref="juhui_repair.model_juhui_repair_order"/> </record>
Of course, abbreviations can also be used:
<act_window id="action_juhui_repair_top" name="Batch top repair order" res_model="juhui.repair.top.wizard" target="new" binding_views="list" view_mode="form" binding_model="juhui.repair.order"/>
Where binding_ The values of views are form or list, which is used to specify whether to display only in the list view.