目录
1、什么是Form视图
2、Form视图的结构
3、源码示例
1、什么是Form视图
Form视图是用于查看和编辑数据库记录的界面。每个数据库模型在Odoo中都有一个Form视图,用于显示该模型的数据。Form视图提供了一个可编辑的界面,允许用户查看和修改数据库记录的字段值。
2、Form视图的结构
-
页眉(Header): 通常包含记录的标题或按钮信息。
-
主体(Body): 包含字段的输入框、选择框、按钮等,用于展示和编辑记录的具体数据。
-
页脚(Footer): 包含操作按钮,例如保存、取消等。
示例
<record id="view_my_model_form" model="ir.ui.view">
<field name="name">my.model.form</field>
<field name="model">my.model</field>
<field name="arch" type="xml">
<form>
<group>
<field name="name"/>
<field name="description"/>
<!-- 其他字段... -->
</group>
<footer>
<button string="Save" class="oe_highlight" type="object" name="save"/>
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
3、源码示例
这里以CRM中的渠道作为讲解
源码:
<record id="crm_lead_view_form" model="ir.ui.view">
<field name="name">crm.lead.form</field>
<field name="model">crm.lead</field>
<field name="arch" type="xml">
<form class="o_lead_opportunity_form" js_class="crm_form">
<header>
<button name="action_set_won_rainbowman" string="Won"
type="object" class="oe_highlight" data-hotkey="w" title="Mark as won"
attrs="{'invisible': ['|','|', ('active','=',False), ('probability', '=', 100), ('type', '=', 'lead')]}"/>
<button name="%(crm.crm_lead_lost_action)d" string="Lost" data-hotkey="l" title="Mark as lost"
type="action" context="{'default_lead_id': active_id}" attrs="{'invisible': ['|', ('type', '=', 'lead'), '&',('active', '=', False),('probability', '<', 100)]}"/>
<button name="%(crm.action_crm_lead2opportunity_partner)d" string="Convert to Opportunity" type="action" help="Convert to Opportunity"
class="oe_highlight" attrs="{'invisible': ['|', ('type', '=', 'opportunity'), ('active', '=', False)]}" data-hotkey="v"/>
<button name="toggle_active" string="Restore" type="object" data-hotkey="z"
attrs="{'invisible': ['|', ('probability', '>', 0), ('active', '=', True)]}"/>
<button name="action_set_lost" string="Lost" type="object" data-hotkey="l" title="Mark as lost"
attrs="{'invisible': ['|', ('type', '=', 'opportunity'), '&', ('probability', '=', 0), ('active', '=', False)]}"/>
<field name="stage_id" widget="statusbar" class="o_field_statusbar"
options="{'clickable': '1', 'fold_field': 'fold'}"
domain="['|', ('team_id', '=', team_id), ('team_id', '=', False)]"
attrs="{'invisible': ['|', ('active', '=', False), ('type', '=', 'lead')]}"/>
</header>
<sheet>
<field name="active" invisible="1"/>
<field name="company_id" invisible="1"/>
<div class="oe_button_box" name="button_box">
<button name="action_schedule_meeting" type="object"
class="oe_stat_button" icon="fa-calendar"
context="{'partner_id': partner_id}"
attrs="{'invisible': [('type', '=', 'lead')]}">
<div class="o_stat_info">
<field name="calendar_event_count" class="o_stat_value"/>
<span class="o_stat_text" attrs="{'invisible': [('calendar_event_count', '<', 2)]}"> Meetings</span>
<span class="o_stat_text" attrs="{'invisible': [('calendar_event_count', '>', 1)]}"> Meeting</span>
</div>
</button>
<button name="action_show_potential_duplicates" type="object"
class="oe_stat_button" icon="fa-star"
attrs="{'invisible': [('duplicate_lead_count', '<', 1)]}">
<div class="o_stat_info">
<field name="duplicate_lead_count" class="o_stat_value"/>
<span class="o_stat_text" attrs="{'invisible': [('duplicate_lead_count', '<', 2)]}">Similar Leads</span>
<span class="o_stat_text" attrs="{'invisible': [('duplicate_lead_count', '>', 1)]}">Similar Lead</span>
</div>
</button>
</div>
<widget name="web_ribbon" title="Lost" bg_color="bg-danger" attrs="{'invisible': ['|', ('probability', '>', 0), ('active', '=', True)]}"/>
<widget name="web_ribbon" title="Won" attrs="{'invisible': [('probability', '<', 100)]}" />
<div class="oe_title">
<h1><field class="text-break" name="name" placeholder="e.g. Product Pricing"/></h1>
<h2 class="d-flex gap-2 g-0 align-items-end pb-3">
<div attrs="{'invisible': [('type', '=', 'lead')]}">
<label for="expected_revenue" class="oe_edit_only pb-1" />
<div class="d-flex align-items-end">
<field name="company_currency" invisible="1"/>
<field name="expected_revenue" class="oe_inline o_input_8ch" widget='monetary' options="{'currency_field': 'company_currency'}"/>
<span class="oe_grey p-2" groups="crm.group_use_recurring_revenues"> + </span>
<span class="oe_grey p-2" groups="!crm.group_use_recurring_revenues"> at </span>
</div>
</div>
<div attrs="{'invisible': [('type', '=', 'lead')]}" groups="crm.group_use_recurring_revenues">
<field name="recurring_revenue" class="oe_inline o_input_10ch" widget="monetary" options="{'currency_field': 'company_currency'}"/>
</div>
<div attrs="{'invisible': [('type', '=', 'lead')]}" groups="crm.group_use_recurring_revenues">
<div class="d-flex align-items-end ps-2">
<field name="recurring_plan" class="oe_inline o_input_12ch" placeholder="E.g. Monthly"
attrs="{'required': [('recurring_revenue', '!=', 0)]}" options="{'no_create': True, 'no_open': True}"/>
<span class="oe_grey p-2"> at </span>
</div>
</div>
<div>
<div class="oe_edit_only d-md-flex align-items-center">
<label for="probability"/>
<div class="d-flex align-items-center">
<button class="ps-0 ps-md-2 btn btn-link" name="action_set_automated_probability" type="object"
attrs="{'invisible': [('is_automated_probability', '=', True)]}">
<i class="fa fa-gear" role="img" title="Switch to automatic probability" aria-label="Switch to automatic probability"></i>
</button>
<small class="oe_grey h6 mb0 d-flex" attrs="{'invisible': [('is_automated_probability', '=', True)]}">
<field class="mb0" name="automated_probability" force_save="1"/> %
</small>
</div>
</div>
<div id="probability" class="d-inline-block">
<field name="is_automated_probability" invisible="1"/>
<field name="probability" widget="float" class="oe_inline o_input_6ch"/>
<span class="oe_grey"> %</span>
</div>
</div>
</h2>
</div>
<group>
<group name="lead_partner" attrs="{'invisible': [('type', '=', 'opportunity')]}">
<!-- Preload all the partner's information -->
<field name="is_partner_visible" invisible='1'/>
<field name="partner_id" widget="res_partner_many2one"
context="{
'default_name': contact_name,
'default_title': title,
'default_street': street,
'default_street2': street2,
'default_city': city,
'default_state_id': state_id,
'default_zip': zip,
'default_country_id': country_id,
'default_function': function,
'default_phone': phone,
'default_mobile': mobile,
'default_email': email_from,
'default_user_id': user_id,
'default_team_id': team_id,
'default_website': website,
'default_lang': lang_code,
'show_vat': True
}" attrs="{'invisible': [('is_partner_visible', '=', False)]}"/>
<field name="partner_name"/>
<label for="street" string="Address"/>
<div class="o_address_format">
<field name="street" placeholder="Street..." class="o_address_street"/>
<field name="street2" placeholder="Street 2..." class="o_address_street"/>
<field name="city" placeholder="City" class="o_address_city"/>
<field name="state_id" class="o_address_state" placeholder="State" options='{"no_open": True}'/>
<field name="zip" placeholder="ZIP" class="o_address_zip"/>
<field name="country_id" placeholder="Country" class="o_address_country" options='{"no_open": True, "no_create": True}'/>
</div>
<field name="website" widget="url" placeholder="e.g. https://www.odoo.com"/>
<field name="lang_active_count" invisible="1"/>
<field name="lang_code" invisible="1"/>
<field name="lang_id" attrs="{'invisible': [('lang_active_count', '<=', 1)]}"
options="{'no_quick_create': True, 'no_create_edit': True, 'no_open': True}"/>
</group>
<group name="opportunity_partner" attrs="{'invisible': [('type', '=', 'lead')]}">
<field name="partner_id"
widget="res_partner_many2one"
string="Customer"
context="{'res_partner_search_mode': type == 'opportunity' and 'customer' or False,
'default_name': contact_name or partner_name,
'default_street': street,
'default_is_company': type == 'opportunity' and contact_name == False,
'default_company_name': type == 'opportunity' and partner_name,
'default_street2': street2,
'default_city': city,
'default_title': title,
'default_state_id': state_id,
'default_zip': zip,
'default_country_id': country_id,
'default_function': function,
'default_phone': phone,
'default_mobile': mobile,
'default_email': email_from,
'default_user_id': user_id,
'default_team_id': team_id,
'default_website': website,
'default_lang': lang_code,
'show_vat': True,
}"
/>
<field name="is_blacklisted" invisible="1"/>
<field name="partner_is_blacklisted" invisible="1"/>
<field name="phone_blacklisted" invisible="1"/>
<field name="mobile_blacklisted" invisible="1"/>
<field name="email_state" invisible="1"/>
<field name="phone_state" invisible="1"/>
<field name="partner_email_update" invisible="1"/>
<field name="partner_phone_update" invisible="1"/>
<label for="email_from" class="oe_inline"/>
<div class="o_row o_row_readonly">
<button name="mail_action_blacklist_remove" class="fa fa-ban text-danger"
title="This email is blacklisted for mass mailings. Click to unblacklist."
type="object" context="{'default_email': email_from}" groups="base.group_user"
attrs="{'invisible': [('is_blacklisted', '=', False)]}"/>
<field name="email_from" string="Email" widget="email"/>
<span class="fa fa-exclamation-triangle text-warning oe_edit_only"
title="By saving this change, the customer email will also be updated."
attrs="{'invisible': [('partner_email_update', '=', False)]}"/>
</div>
<label for="phone" class="oe_inline"/>
<div class="o_row o_row_readonly">
<button name="phone_action_blacklist_remove" class="fa fa-ban text-danger"
title="This phone number is blacklisted for SMS Marketing. Click to unblacklist."
type="object" context="{'default_phone': phone}" groups="base.group_user"
attrs="{'invisible': [('phone_blacklisted', '=', False)]}"/>
<field name="phone" widget="phone"/>
<span class="fa fa-exclamation-triangle text-warning oe_edit_only"
title="By saving this change, the customer phone number will also be updated."
attrs="{'invisible': [('partner_phone_update', '=', False)]}"/>
</div>
<field name="lost_reason_id" attrs="{'invisible': [('active', '=', True)]}"/>
<field name="date_conversion" invisible="1"/>
<field name="user_company_ids" invisible="1"/>
</group>
<group name="lead_info" attrs="{'invisible': [('type', '=', 'opportunity')]}">
<label for="contact_name"/>
<div class="o_row">
<field name="contact_name"/>
<field name="title" placeholder="Title" domain="[]" options='{"no_open": True}'/>
</div>
<field name="is_blacklisted" invisible="1"/>
<field name="phone_blacklisted" invisible="1"/>
<field name="email_state" invisible="1"/>
<field name="phone_state" invisible="1"/>
<field name="partner_email_update" invisible="1"/>
<field name="partner_phone_update" invisible="1"/>
<label for="email_from_group_lead_info" class="oe_inline"/>
<div class="o_row o_row_readonly">
<button name="mail_action_blacklist_remove" class="fa fa-ban text-danger"
title="This email is blacklisted for mass mailings. Click to unblacklist."
type="object" context="{'default_email': email_from}" groups="base.group_user"
attrs="{'invisible': [('is_blacklisted', '=', False)]}"/>
<field name="email_from" id="email_from_group_lead_info" string="Email" widget="email"/>
<span class="fa fa-exclamation-triangle text-warning oe_edit_only"
title="By saving this change, the customer email will also be updated."
attrs="{'invisible': [('partner_email_update', '=', False)]}"/>
</div>
<field name="email_cc" groups="base.group_no_one"/>
<field name="function"/>
<label for="phone_group_lead_info" class="oe_inline"/>
<div class="o_row o_row_readonly">
<button name="phone_action_blacklist_remove" class="fa fa-ban text-danger"
title="This phone number is blacklisted for SMS Marketing. Click to unblacklist."
type="object" context="{'default_phone': phone}" groups="base.group_user"
attrs="{'invisible': [('phone_blacklisted', '=', False)]}"/>
<field name="phone" id="phone_group_lead_info" widget="phone"/>
<span class="fa fa-exclamation-triangle text-warning oe_edit_only"
title="By saving this change, the customer phone number will also be updated."
attrs="{'invisible': [('partner_phone_update', '=', False)]}"/>
</div>
<label for="mobile" class="oe_inline"/>
<div class="o_row o_row_readonly">
<button name="phone_action_blacklist_remove" class="fa fa-ban text-danger"
title="This phone number is blacklisted for SMS Marketing. Click to unblacklist."
type="object" context="{'default_phone': mobile}" groups="base.group_user"
attrs="{'invisible': [('mobile_blacklisted', '=', False)]}"/>
<field name="mobile" widget="phone" string="Mobile"/>
</div>
</group>
<field name="type" invisible="1"/>
<group attrs="{'invisible': [('type', '=', 'lead')]}">
<field name="user_id"
context="{'default_sales_team_id': team_id}" widget="many2one_avatar_user"/>
<label for="date_deadline">Expected Closing</label>
<div class="o_lead_opportunity_form_inline_fields">
<field name="date_deadline" nolabel="1" class="oe_inline"/>
<field name="priority" widget="priority" nolabel="1" class="oe_inline align-top"/>
</div>
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/>
</group>
<group attrs="{'invisible': [('type', '=', 'opportunity')]}">
<field name="user_id"
context="{'default_sales_team_id': team_id}" widget="many2one_avatar_user"/>
<field name="team_id" options="{'no_open': True, 'no_create': True}"/>
</group>
<group name="lead_priority" attrs="{'invisible': [('type', '=', 'opportunity')]}">
<field name="priority" widget="priority"/>
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/>
</group>
</group>
<field attrs="{'invisible': [('team_id', '=', False)]}"
name="lead_properties" nolabel="1" columns="2" hideKanbanOption="1"/>
<notebook>
<page string="Internal Notes" name="internal_notes">
<field name="description" placeholder="Add a description..." options="{'collaborative': true}" />
</page>
<page name="extra" string="Extra Info" attrs="{'invisible': [('type', '=', 'opportunity')]}">
<group>
<group string="Email" groups="base.group_no_one">
<field name="message_bounce" readonly="1"/>
</group>
<group string="Marketing" name="categorization">
<field name="company_id"
groups="base.group_multi_company"
options="{'no_create': True}"/>
<field name="campaign_id" options="{'create_name_field': 'title', 'always_reload': True}"/>
<field name="medium_id"/>
<field name="source_id"/>
<field name="referred"/>
</group>
<group string="Analysis">
<field name="date_open"/>
<field name="date_closed"/>
</group>
</group>
</page>
<page name="lead" string="Extra Information" attrs="{'invisible': [('type', '=', 'lead')]}">
<group>
<group string="Contact Information">
<field name="partner_name"/>
<label for="street_page_lead" string="Address"/>
<div class="o_address_format">
<field name="street" id="street_page_lead" placeholder="Street..." class="o_address_street"/>
<field name="street2" placeholder="Street 2..." class="o_address_street"/>
<field name="city" placeholder="City" class="o_address_city"/>
<field name="state_id" class="o_address_state" placeholder="State" options='{"no_open": True}'/>
<field name="zip" placeholder="ZIP" class="o_address_zip"/>
<field name="country_id" placeholder="Country" class="o_address_country" options='{"no_open": True, "no_create": True}'/>
</div>
<field name="website" widget="url" placeholder="e.g. https://www.odoo.com"/>
<field name="lang_active_count" invisible="1"/>
<field name="lang_id" attrs="{'invisible': [('lang_active_count', '<=', 1)]}"
options="{'no_quick_create': True, 'no_create_edit': True, 'no_open': True}"/>
</group>
<group class="mt48">
<label for="contact_name_page_lead"/>
<div class="o_row">
<field name="contact_name" id="contact_name_page_lead"/>
<field name="title" placeholder="Title" domain="[]" options='{"no_open": True}'/>
</div>
<field name="function"/>
<label for="mobile_page_lead" class="oe_inline"/>
<div class="o_row o_row_readonly">
<button name="phone_action_blacklist_remove" class="fa fa-ban text-danger"
title="This phone number is blacklisted for SMS Marketing. Click to unblacklist."
type="object" context="{'default_phone': mobile}" groups="base.group_user"
attrs="{'invisible': [('mobile_blacklisted', '=', False)]}"/>
<field name="mobile" id="mobile_page_lead" widget="phone"/>
</div>
</group>
<group string="Marketing">
<field name="campaign_id" options="{'create_name_field': 'title', 'always_reload': True}"/>
<field name="medium_id" />
<field name="source_id" />
<field name="referred"/>
</group>
<group string="Tracking" name="Misc">
<field name="company_id"
groups="base.group_multi_company"
options="{'no_create': True}"/>
<field name="team_id" options="{'no_open': True, 'no_create': True}"/>
<field name="day_open" />
<field name="day_close"/>
<field name="type" invisible="1"/>
</group>
</group>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids" options="{'post_refresh': 'recipients'}"/>
</div>
</form>
</field>
</record>
参数解释:
-
<record>
元素:id="crm_lead_view_form"
:视图的唯一标识符,用于在其他地方引用该视图。model="ir.ui.view"
:指定模型为ir.ui.view
,这是Odoo中用于存储用户界面视图定义的模型。
-
<field>
元素:name="name"
:视图的名称,用于在Odoo界面中标识该视图。model="crm.lead"
:指定模型为crm.lead
,表示该视图关联到crm.lead
模型。
-
<form>
元素:class="o_lead_opportunity_form"
:为视图添加CSS类名,可以用于自定义视图的样式。js_class="crm_form"
:为视图添加JavaScript类名,可用于自定义视图的行为。
-
<header>
元素:- 包含了在 Form 视图的顶部显示的按钮和字段,如 "Won"、"Lost"、"Convert to Opportunity" 等。
-
<button>
元素:name
:按钮的方法名称,点击按钮时会触发该方法。string
:按钮上显示的文本。type
:按钮的类型,可以是 "object" 或 "action"。class
:CSS类,用于自定义按钮的样式。data-hotkey
:定义热键,用户可以通过键盘快捷键触发按钮。context
:上下文,传递给按钮触发的方法。
-
<field>
元素:name="stage_id"
:展示了一个阶段的字段,使用了widget="statusbar"
,显示为状态栏。domain
:定义了字段的域(过滤条件)。
-
<sheet>
元素:- 包含了 Form 视图主体的内容,包括字段、按钮、页签等。
-
<widget>
元素:name="web_ribbon"
:自定义小部件,用于在记录上显示标签,如 "Lost" 或 "Won"。title
:小部件的标题。bg_color
:背景颜色,用于区分不同的标签。
-
<div>
元素:class="oe_button_box"
:包含按钮的容器,用于自定义按钮的布局。
-
<notebook>
元素:- 包含了多个页签,每个页签使用
<page>
元素定义。这里有 "Internal Notes"、"Extra Info" 和 "Extra Information" 三个页签。
- 包含了多个页签,每个页签使用
-
<group>
元素:- 包含了一组相关的字段,可以通过
attrs
属性控制字段组的可见性。
- 包含了一组相关的字段,可以通过
-
<field>
元素:widget="many2one_avatar_user"
:使用了many2one_avatar_user
小部件,用于选择用户,并显示用户的头像。
-
<button>
元素:name="action_schedule_meeting"
:触发一个方法来安排会议。context
:定义了在触发方法时传递给方法的上下文。
-
<widget>
元素:name="web_ribbon"
:自定义小部件,用于显示记录的标签。
-
<notebook>
中的<page>
元素:- 包含了不同的信息页,例如 "Internal Notes"、"Extra Info" 和 "Extra Information"。
-
<div>
元素:class="oe_chatter"
:包含了关于记录的讨论和活动信息。
-
<field>
元素:name="message_follower_ids"
、name="activity_ids"
、name="message_ids"
:用于显示关注者、活动和消息的信息。