odoo 开发入门教程系列-添加修饰
添加修饰
我们的房地产模块现在从商业角度来看是有意义的。我们创建了特定的视图,添加了几个操作按钮和约束。然而,我们的用户界面仍然有点粗糙。我们希望为列表视图添加一些颜色,并使一些字段和按钮有条件地消失。例如,当房产已出售或取消时,“已售出”和“取消”按钮应消失,因为此时不再允许更改状态。
参考: 文档关联的主题可以查看 Views.
内联视图(Inline Views)
在房地产模块中,我们为房产添加了一个报价列表。我们通过以下代码简单地添加了offer_ids
字段:
<field name="offer_ids"/>
该字段使用estate.properties.offer
的特定视图。在某些情况下,我们希望定义一个仅在表单视图上下文中使用的特定列表视图。例如,我们希望显示链接到房产类型的房产列表。然而,为了清楚起见,我们只想显示3个字段:名称、预期价格和状态。
为此,我们可以定义内联列表视图。内联列表视图直接在表单视图中定义。例如:
from odoo import fields, models
class TestModel(models.Model):
_name = "test.model"
_description = "Test Model"
description = fields.Char()
line_ids = fields.One2many("test.model.line", "model_id")
class TestModelLine(models.Model):
_name = "test.model.line"
_description = "Test Model Line"
model_id = fields.Many2one("test.model")
field_1 = fields.Char()
field_2 = fields.Char()
field_3 = fields.Char()
<form>
<field name="description"/>
<field name="line_ids">
<tree>
<field name="field_1"/>
<field name="field_2"/>
</tree>
</field>
</form>
在test.model
的表单视图中,我们使用 field_1
和field_2
为 test.model.line
定义了列表视图
<record id="event_tag_category_view_form" model="ir.ui.view">
<field name="name">event.tag.category.view.form</field>
<field name="model">event.tag.category</field>
<field name="arch" type="xml">
<form string="Event Category">
<sheet>
<div class="oe_title">
<h1><field nolabel="1" name="name"/></h1>
</div>
<group>
<field name="tag_ids" context="{'default_category_id': active_id}">
<tree string="Tags" editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="color" widget="color_picker"/>
</tree>
</field>
</group>
</sheet>
</form>
</field>
</record>
练习--添加一个内联视图
添加
One2many
字段property_ids
到estate.property.type
模型在
estate.property.type
表单视图中添加字段,如下图
修改odoo14\custom\estate\models\estate_property_type.py
property_ids = fields.One2many('estate.property', 'property_type_id')
修改odoo14\custom\estate\views\estate_property_type_views.xml
,添加estate_property_type_view_form
<record id="estate_property_type_view_form" model="ir.ui.view">
<field name="name">estate.property.type.form</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<form string="Property Type">
<sheet>
<div class="oe_title">
<h1><field nolabel="1" name="name"/></h1>
</div>
<field name="property_ids">
<tree string="Properties" editable="bottom">
<field name="name" string="Title"/>
<field name="expected_price" string="Expected Price"/>
<field name="state" string="Status"/>
</tree>
</field>
</sheet>
</form>
</field>
</record>
重启服务,验证效果
组件(Widget)
参考: 查看本节主题关联文档Field Widgets.
每当我们将字段添加到模型中时,我们(几乎)从来不用担心这些字段在用户界面中会是什么样子。例如,为Date
字段提供的日期选择器,One2many
字段自动显示为列表。Odoo根据字段类型选择正确的“widget”。
然而,在某些情况下,我们需要某个字段的特定表示,这种特定表示的实现,归功于widget
属性。在使用widget=“many2many_tags”
属性时,我们已经将其用于tag_ids
字段。如果我们没有使用它,那么该字段将显示为列表。
每个字段类型都有一系列组件,可用于微调其显示。一些组件也有额外的选项。在Field Widgets中可以找到详尽的列表。
练习--使用状态栏组件
使用 statusbar
组件来展示的 estate.property
的state
,如下图:
提示: 一个简单的示例.
<field name="state" widget="statusbar" statusbar_visible="open,posted,confirm"/>
警告
相同字段,只能在列表或表单视图中只添加一次,不支持多次添加。
同一个字段,如果展示多次,会以最后一次的样式统一展示。
编辑odoo14\custom\estate\views\estate_property_views.xml
修改estate_property_view_form
表单视图的<header>
元素
<header>
<button name="set_property_sold" type="object" string="SOLD"></button>
<button name="set_property_canceled" type="object" string="CANCEL"></button>
<!-- <field>元素为本次新增内容 -->
<field name="state" widget="statusbar" statusbar_visible="New,Offer Received,Offer Accepted,Sold,Canceled"/>
</header>
去掉<sheet>
元素中的state
字段
<field name="state" string="Status"></field>
注意:如果不去掉上述代码,这里的样式将会覆盖statusbar
的state
字段样式,如下:
说明:statusbar_visible
属性值为state
字段可选值(字段值的selection
列表中二元组、单元组中的value
,即元组第一个元素)字符串列表,控制状态栏显示那些状态,如果statusbar_visible
值不为空字符串,则仅显示位于statusbar_visible
属性值中指定的状态,以及视图归属模型中对应字段(例中为state
)的default
属性指定的状态(不管默认值是否在statusbar_visible
属性值中),否则展示全部状态。此外,属性值在视图中的展示顺序,取决于字段可选值在public.ir_model_fields_selection
表中对应sequence
字段值大小,按该字段大小从左到右升序排序属性值
刷新浏览器,验证效果:
列表排序
参考: 本节主题关联文档Models.
在前面的练习中,我们创建了几个列表视图。然而,我们没有指定默认情况下记录必须按哪个顺序展示。对于许多业务案例来说,这是一件非常重要的事情。例如,在我们的房地产模块中,我们希望在列表顶部显示最高报价
Model
odoo提供了几种设置默认顺序的方法。最常见的方法是直接在模型中定义_order
属性。这样,检索到的记录将遵循确定性顺序,该顺序在所有视图中都是一致的,包括以编程方式搜索记录时。默认情况下,没有指定顺序,因此将根据不确定的顺序检索记录,取决于PostgreSQL。
_order
属性接收一个字符串,该字符串包含将用于排序的字段列表。它将转换为SQL中的order_by子句。例如:
from odoo import fields, models
class TestModel(models.Model):
_name = "test.model"
_description = "Test Model"
_order = "id desc"
description = fields.Char()
如上,记录将按id
降序排序,意味着最高的排在最上面。
练习--添加模型排序
在对应模型中添加一下排序
Model | Order |
---|---|
estate.property |
按 ID降序 |
estate.property.offer |
按Price降序 |
estate.property.tag |
Name |
estate.property.type |
Name |
此处练习比较简单,我就不贴实践代码了,参考上述示例
重启服务,验证效果
View
可以在模型级别进行排序,它有个优点,即即在检索记录列表的任何地方都有一致的顺序。也可以通过default_order
直接在视图中定义指定排序顺序 (示例)。
<record id="crm_activity_report_view_tree" model="ir.ui.view">
<field name="name">crm.activity.report.tree</field>
<field name="model">crm.activity.report</field>
<field name="arch" type="xml">
<tree default_order="date desc">
<field name="date"/>
<field name="author_id"/>
<field name="mail_activity_type_id"/>
<field name="body"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
手工(Manual)
模型排序和视图排序都允许在排序记录时具有灵活性,但仍有一种情况需要考虑:手动排序。用户可能希望根据业务逻辑对记录进行排序。例如,在我们的房地产模块中,我们希望手动对房产类型进行排序。将最常用的类型显示在列表的顶部确实很有用。如果我们的房地产经纪公司主要销售房子,那么在“公寓(Apartment)”之前出现“房子(House)”会更方便。
为此,将sequence
字段与handle
组件结合使用。显然,sequence
字段必须是_order
属性中的第一个字段。
练习--添加手工排序
- 添加以下排序字段
Model | Field | Type |
---|---|---|
estate.property.type |
Sequence | Integer |
- 使用正确的组件,添加
sequence
到estate.property.type
列表视图
sequence = fields.Integer('Sequence', default=1, help="Used to order stages. Lower is better.")
<record id="crm_stage_tree" model="ir.ui.view">
<field name="name">crm.stage.tree</field>
<field name="model">crm.stage</field>
<field name="arch" type="xml">
<tree string="Stages" multi_edit="1">
<field name="sequence" widget="handle"/>
<field name="name" readonly="1"/>
<field name="is_won"/>
<field name="team_id"/>
</tree>
</field>
</record>
修改odoo14\custom\estate\models\estate_property_type.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from odoo import models, fields
class EstatePropertyType(models.Model):
_name = 'estate.property.type'
_description = 'estate property type'
_order = 'sequence,name'
name = fields.Char(string='name', required=True)
property_ids = fields.One2many('estate.property', 'property_type_id')
sequence = fields.Integer('Sequence', default=1, help="Used to order type")
_sql_constraints = [('check_name', 'unique(name)', 'Type name must be unique !')]
修改odoo14\custom\estate\views\estate_property_type_views.xml
中estate_property_type_view_tree
<record id="estate_property_type_view_tree" model="ir.ui.view">
<field name="name">estate.property.type.tree</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<tree string="PropertyTypes">
<field name="sequence" widget="handle"/>
<field name="name"/>
</tree>
</field>
</record>
重启服务,验证效果(可手工拖动记录排序)
属性和选项(Attributes and options)
详细说明所有允许对视图外观进行微调的可用特性是令人望而却步的。因此,我们将挑选最常见的特性进行说明。
表单(Form)
目标: 本节末尾中,地产表单视图将拥有以下:
- 有条件的显示按钮和字段
- 标签颜色
预期效果动画地址:https://www.odoo.com/documentation/14.0/zh_CN/_images/form.gif
在我们的房地产模块中,我们希望修改某些字段的行为。例如,我们不希望能够从表单视图创建或编辑房产类型。相反,我们希望在其相应的菜单中处理类型。我们还想给标签增加一种颜色。为了添加这些定制化行为,我们可以将options
属性添加到几个字段组件中。
练习--添加组件选项
- 添加合适的选项到
property_type_id
字段,避免在房产表单视图中创建活编辑房产类型。查看Many2one组件文档 获取更多信息 - 添加以下字段:
Model | Field | Type |
---|---|---|
estate.property.tag |
Color | Integer |
然后添加合适的选项到 tag_ids
字段以便在标签上添加颜色选择器。查看FieldMany2ManyTags组件文档 获取更多详细信息
编辑odoo14\custom\estate\models\estate_property.py
修改
property_type_id = fields.Many2one("estate.property.type", string="PropertyType")
为
property_type_id = fields.Many2one("estate.property.type", string="PropertyType", options="{'no_create_edit': True}")
重启服务,验证效果
如下,看不到创建和编辑入口了
编辑odoo14\custom\estate\models\estate_property_tag.py
,新增color
字段:
color = fields.Integer(string='Color')
修改odoo14\custom\estate\views\estate_property_views.xml
estate_property_view_form
中
<field name="tag_ids" widget="many2many_tags"/>
为
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}"/>
重启服务,验证效果
在"一些用户界面"章节中,我们看到保留字段用于特定行为。例如,active
字段用于自动筛选出非活动记录。我们还添加了state
作为保留字段。现在是使用它的时候了!state
字段与视图中的states
属性结合使用,以有条件地显示按钮。
练习--有条件的显示按钮
使用states
属性来显示有条件的显示头部按钮,如本节目标中所述(注意修改状态时“已售出”和“取消”按钮的变化)
提示: 请不要犹豫在Odoo XML文件中搜索states=
以获得一些示例
修改odoo14\custom\estate\views\estate_property_views.xml
表单视图中的<header>
<header>
<button name="set_property_sold" type="object" states="Offer Accepted" string="SOLD"></button>
<button name="set_property_canceled" type="object" states="New,Offer Received,Offer Accepted" string="CANCEL"></button>
<field name="state" widget="statusbar" statusbar_visible="New,Offer Received,Offer Accepted,Sold,Canceled"/>
</header>
说明:
第一个按钮的states
配置,意为仅在当前记录state
的值Offer Accepted
时显示该按钮
第一个按钮的states
配置,意为仅在当前记录state
的值New
、Offer Received
、Offer Accepted
时显示该按钮
刷新浏览器验证(可通过修改数据库中对应记录的state
值来观察按钮的显示变化)
更普遍的,多亏attrs
属性,可以根据其他字段的值使字谋个字段 不可见(invisible
)、只读(readonly
)或必需(required
。注意, invisible
也可以应用于视图的其他元素,如按钮( button
)或组( group
)。
attrs
为一个以属性为key,以domain
为值的字典。 domain
给出了应用该属性的条件。例如:
<form>
<field name="description" attrs="{'invisible': [('is_partner', '=', False)]}"/>
<field name="is_partner" invisible="1"/>
</form>
这意味着当 is_partner
为 False
时description
字段不可见。需要注意的是,attrs
中使用的字段必须出现在视图中。如果它不应该显示给用户,我们可以使用invisible
属性来隐藏它。
练习--使用 attrs
- 当没有花园(garden)时,设置
estate.property
表单视图中的花园面积(garden area)和朝向(garden orientation)不可见 - 一单设置了报价状态,设置’Accept’ 和‘Refuse’ 按钮不可见
- 当房产状态为
Offer Accepted
,Sold
或Canceled
时,不允许添加报价。为此使用readonly
attrs
.
警告
在视图中使用(条件)
readonly
属性可能有助于防止数据输入错误,但请记住,它不会提供任何级别的安全性!服务器端没有进行检查,因此始终可以通过RPC调用在字段上进行写入。
修改odoo14\custom\estate\views\estate_property_views.xml
表单视图
<page string="Description">
<group>
<field name="description"></field>
<field name="bedrooms"></field>
<field name="living_area"></field>
<field name="facades"></field>
<field name="garage"></field>
<field name="garden"></field>
<field name="garden_area" attrs="{'invisible': [('garden', '=', False)]}"></field>
<field name="garden_orientation" attrs="{'invisible': [('garden', '=', False)]}"></field>
<field name="total_area" string="Total Area"></field>
</group>
</page>
修改offer_ids
属性
<page string="Offers">
<field name="offer_ids" attrs="{'readonly': [('state', 'in', ['Offer Accepted','Sold','Canceled'])]}"/>
</page>
说明: in
表示在列表中,反之使用 not in
修改odoo14\custom\estate\views\estate_property_offer_views.xml
给button
新增属性
<tree string="PropertyOffers">
<field name="price" string="Price"/>
<field name="partner_id" string="partner ID"/>
<field name="validity" string="Validity(days)"/>
<field name="date_deadline" string="Deadline"/>
<button name="action_accept_offer" string="" type="object" icon="fa-check" attrs="{'invisible': [('status', 'in', ['Accepted','Refused'])]}"/>
<button name="action_refuse_offer" string="" type="object" icon="fa-times" attrs="{'invisible': [('status', 'in', ['Accepted','Refused'])]}"/>
<field name="status" string="Status"/>
</tree>
刷新浏览器,验证效果
列表(List)
当模型只有几个字段时,可以通过列表视图直接编辑记录,而不必打开表单视图。在房地产示例中,不需要打开窗体视图来添加报价或创建新标签。这可以通过editable
属性实现。
练习--使列表视图可编辑
让estate.properties.offer
和estate.properties.tag
列表视图可编辑。
此外,当一个模型有很多字段时,很可能会在列表视图中添加太多字段,使其变得不清晰。另一种方法是添加字段,并让这些字段可以有选择的被隐藏。这可以通过optional
属性实现。
练习-使字段成为可选字段
默认情况下,将estate.properties
列表视图中的字段date_availability
设置为可选,默认隐藏。
修改odoo14\custom\estate\views\estate_property_offer_views.xml
中的tree
视图中的<tree>
元素,增加editable
属性:
<tree string="PropertyOffers" editable="top">
刷新浏览器查看
修改odoo14\custom\estate\views\estate_property_views.xml
estate_property_view_tree
中的<tree>
元素
<tree string="estate property" editable="top"><!--editable属性为本次新增-->
<field name="name" string="Title"/>
<field name="postcode" string="Postcode"/>
<field name="tag_ids" string="Tags" widget="many2many_tags" options="{'color_field': 'color'}"/><!--本次新增字段-->
<field name="bedrooms" string="Bedrooms"/>
<field name="living_area" string="Living Area"/>
<field name="expected_price" string="Expected Price"/>
<field name="selling_price" string="Selling Price"/>
<field name="date_availability" string="Avalilable Form" optional="hide"/>
<field name="property_type_id" string="Property Type"/>
</tree>
说明:
editable="value"
,其中value
可选值为top|bottom
,表示点击创建记录时,待创建记录出现在列表的顶部(value=top
)还是底部(value=bottom
)。optional="value"
,value
可选值为hide
(隐藏),show
(显示)
刷新浏览器验证
最后,颜色代码有助于直观地强调记录。例如,在房地产模块中,我们希望以红色显示拒绝的报价,以绿色显示接受的报价。这可以通过 decoration-{$name}
属性实现(有关完整列表,请参阅 decorations):
<tree decoration-success="is_partner==True">
<field name="name">
<field name="is_partner" invisible="1">
</tree>
is_partner
为True
的记录将显示为绿色。
练习--添加一些装饰
在 estate.property
列表视图中:
- 收到报价的房产显示为绿色
- 已接受报价的房产显示为绿色,并加粗显示
- 已出售房产显示为禁用(
muted
)
修改odoo14\custom\estate\views\estate_property_views.xml
,给列表视图<tree>
元素增加decoration-x
属性:
<tree string="estate property" editable="top" decoration-success="state in ['Offer Received','Offer Accepted']" decoration-bf="state == 'Offer Accepted'" decoration-muted="state == 'Sold'">
刷新浏览器验证
搜索(Search)
Reference: 查看主题关联文档Search 和 Search defaults
本章目标:在本节结束时,默认情况下将过滤可用的属性,搜索居住区域将返回面积大于给定数字的结果。
预期效果动画地址:https://www.odoo.com/documentation/14.0/zh_CN/_images/search.gif
最后但并非最不重要的是,我们希望在搜索时应用一些调整。首先,我们希望在访问房产列表时默认应用“Avaliable”筛选器。为了实现这一点,我们需要使用search_default_{$name}
操作上下文,其中{$name}
为过滤器名称,即搜索视图中定义的<field>
、<filter>
元素的name
属性值。这意味着我们可以在操作级别定义默认激活的过滤器。
<!-- Opportunities by user and team Search View -->
<record id="crm_opportunity_report_view_search" model="ir.ui.view">
<field name="name">crm.lead.search</field>
<field name="model">crm.lead</field>
<field name="priority">32</field>
<field name="arch" type="xml">
<search string="Opportunities Analysis">
...
<filter name="opportunity" string="Opportunity" domain="[('type','=','opportunity')]" help="Show only opportunity"/>
...
<record id="crm_opportunity_report_action" model="ir.actions.act_window">
<field name="name">Pipeline Analysis</field>
<field name="res_model">crm.lead</field>
<field name="view_mode">pivot,graph,tree,form</field>
<field name="search_view_id" ref="crm.crm_opportunity_report_view_search"/>
<field name="context">{'search_default_opportunity': True, 'search_default_current': True}</field>
...
练习--添加默认过滤器
在estate.properties
action
中,默认选择‘Available’筛选器。
修改odoo14\custom\estate\views\estate_property_views.xml
link_estate_property_action
<record id="link_estate_property_action" model="ir.actions.act_window">
<field name="name">Properties</field>
<field name="res_model">estate.property</field>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_state': True}</field><!--新增内容-->
</record>
重启服务,刷新浏览器验证
我们模块的另一个有用的改进是能够按居住面积高效搜索。实际上,用户需要搜索“至少”给定面积的房产。期望用户能够找到一个精确居住面积的房产是不现实的。总是可以进行自定义搜索,但这很不方便。
搜索视图的<field>
元素可以包含一个filter_domain
,它会覆盖为搜索给定字段而生成的domain
。在给定domain
中,self
表示用户输入的值。在下面的示例中,它用于搜索 name
和 description
字段。
<search string="Test">
<field name="description" string="Name and description"
filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"/>
</group>
</search>
练习--改变居住面积搜索
添加一个 filter_domain
到居住面积,以搜索面积大于等于给值的房产。
修改odoo14\custom\estate\views\estate_property_views.xml
estate_property_search_view
,增加living_area
字段
<search string="Estate Property">
<!-- 搜索 -->
<field name="name" string="Title" />
<field name="postcode" string="Postcode"></field>
<field name="living_area" string="LivingArea" filter_domain="[('living_area', '>=', self)]"/> <!--本次新增-->
<separator/>
<!-- 筛选 -->
<filter string="Available" name="state" domain="['|',('state', '=', 'New'),('state', '=', 'Offer Received')]"></filter>
<filter name="bedrooms" domain="[('bedrooms', '>', 3)]"></filter>
<filter name="bedrooms and selling_price" domain="[('bedrooms', '>', 2),('selling_price', '>=', 1000)]"></filter>
<!-- 分组 -->
<group expand="1" string="Group By">
<filter string="朝向" name="garden_orientation" context="{'group_by':'garden_orientation'}"/>
</group>
</search>
重启服务,刷新页面后验证
统计按钮(Stat Buttons)
在本节的末尾,房产类型表单视图上会有一个统计按钮,当单击该按钮时,它会显示与给定类型的房产相关的所有报价的列表。
预期效果动画地址:https://www.odoo.com/documentation/14.0/zh_CN/_images/stat_button.gif
在我们的房地产模块中,我们希望快速链接到与给定房产类型相关的报价,正如目标描述中展示的那样。
提示:通过在Odoo代码库中查找“oe_stat_button”,以获取一些示例。
本次练习将引入Related fields的概念。理解它的最简单方法是将其视为计算的字段的特殊情况。以下description
字段的定义:
...
partner_id = fields.Many2one("res.partner", string="Partner")
description = fields.Char(related="partner_id.name")
等价于:
...
partner_id = fields.Many2one("res.partner", string="Partner")
description = fields.Char(compute="_compute_description")
@api.depends("partner_id.name")
def _compute_description(self):
for record in self:
record.description = record.partner_id.name
每当partner
的name
改变时,description
也会被改变。
练习--添加统计按钮到房产类型
- 添加
property_type_id
到estate.property.offer
。 我们可以将其定义为property_id.property_type_id
上的关联字段,并将其设置为存储。
因为此字段,报价将在创建时链接到房产类型。您可以将该字段添加到报价列表视图中,以确保其正常工作。.
- 添加
offer_ids
到estate.property.type
,该字段为前面步骤定义的字段的One2many
inverse
- 添加
offer_count
到estate.property.type
。该字段为一个计算的字段,用于统计给定房产类型的报价的数量 (使用offer_ids
进行计算)。
此时,你已经掌握了了解有多少报价链接到一个房产类型的所有必要的信息。如果有疑问,请将offer_ids
和offer_count
直接添加到视图中。下一步是在单击统计按钮时显示列表。
- 在
estate.properties.type
上创建一个统计按钮,指向estate.property.offer
action。这意味着你应该使用type=“action”
属性
此时,点击统计按钮,应该显示所有报价。我们仍然需要过滤的报价。
在
estate.property.offer
action中添加一个domain
, 将property_type_id
定义为等于active_id
(=当前记录, 这里是一个示例)<record id="act_event_registration_from_event" model="ir.actions.act_window">
<field name="res_model">event.registration</field>
<field name="name">Attendees</field>
<field name="view_mode">kanban,tree,form,calendar,graph</field>
<field name="domain">[('event_id', '=', active_id)]</field>
...
</record>
编辑odoo14\custom\estate\models\estate_property_offer.py
,修改
from odoo import models, fields
为
from odoo import models, fields, api
新增以下字段:
property_type_id = fields.Many2one(related="property_id.property_type_id", store=True)
修改odoo14\custom\estate\models\estate_property_type.py
,新增offer_ids
,offer_count
字段,新增_compute_offer_count
函数
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from odoo import models, fields, api
class EstatePropertyType(models.Model):
_name = 'estate.property.type'
_description = 'estate property type'
_order = 'sequence, name'
sequence = fields.Integer('Sequence', default=1, help="Used to order type")
name = fields.Char(string='name', required=True)
property_ids = fields.One2many('estate.property', 'property_type_id')
offer_ids = fields.One2many('estate.property.offer', 'property_type_id')
offer_count = fields.Integer(compute='_compute_offer_count')
_sql_constraints = [('check_name', 'unique(name)', 'Type name must be unique !')]
@api.depends('offer_ids.price')
def _compute_offer_count(self):
for record in self:
record.offer_count = sum(record.mapped('offer_ids.price'))
修改odoo14\custom\estate\views\estate_property_type_views.xml
,新增display_offers_for_given_estate_property_action
,button_box
div
元素
<?xml version="1.0"?>
<odoo>
<record id="estate_property_type_action" model="ir.actions.act_window">
<field name="name">Property Types</field>
<field name="res_model">estate.property.type</field>
<field name="view_mode">tree,form</field>
</record>
<!--display_offers_for_given_estate_property_action为本次新增元素-->
<record id="display_offers_for_given_estate_property_action" model="ir.actions.act_window">
<field name="name">Property Offers</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">estate.property.offer</field>
<field name="view_mode">tree</field>
<field name="domain">[('property_type_id', '=', active_id)]</field>
<field name="context">{'default_event_id': active_id}</field>
</record>
<record id="estate_property_type_view_tree" model="ir.ui.view">
<field name="name">estate.property.type.tree</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle"></field>
<field name="name" string="Property Type"/>
</tree>
</field>
</record>
<record id="estate_property_type_view_form" model="ir.ui.view">
<field name="name">estate.property.type.form</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<form string="Property Type">
<sheet>
<!--button_box为本次新增元素-->
<div class="oe_button_box" name="button_box" >
<button class="oe_stat_button" name="%(display_offers_for_given_estate_property_action)d"
string="" type="action" icon="fa-money">
<field string="Offers" widget="statinfo" name="offer_count"></field>
</button>
</div>
<div class="oe_title">
<h1><field nolabel="1" name="name"/></h1>
</div>
<field name="property_ids">
<tree string="Properties" editable="bottom">
<field name="name" string="Title"/>
<field name="expected_price" string="Expected Price"/>
<field name="state" string="Status"/>
</tree>
</field>
</sheet>
</form>
</field>
</record>
</odoo>
重启服务,刷新浏览器验证
通过按钮跳转后带来的问题
点击浏览器回退键,面包屑显重复显示了,如下,暂时未找到解决方案
odoo 开发入门教程系列-添加修饰的更多相关文章
- WPF入门教程系列(一) 创建你的第一个WPF项目
WPF入门教程系列(一) 创建你的第一个WPF项目 WPF基础知识 快速学习绝不是从零学起的,良好的基础是快速入手的关键,下面先为大家摞列以下自己总结的学习WPF的几点基础知识: 1) C#基础语法知 ...
- Android Studio JNI开发入门教程
Android Studio JNI开发入门教程 2016-08-29 14:38 3269人阅读 评论(0) 收藏 举报 分类: JNI(3) 目录(?)[+] 概述 在Andorid ...
- SeaJS入门教程系列之使用SeaJS(二)
SeaJS入门教程系列之使用SeaJS(二) 作者: 字体:[增加 减小] 类型:转载 时间:2014-03-03我要评论 这篇文章主要介绍了SeaJS入门教程系列之使用SeaJS,着重介绍了SeaJ ...
- 移动H5开发入门教程:12点webAPP前端开发经验
如果你是一名移动H5前端开发人员,25学堂的小编认为下面的分享的12点webAPP前端开发经验是你必须掌握的基础知识点.算是一篇移动H5开发入门教程吧! 1. viewport:也就是可视区域.对于桌 ...
- C#,ArcGIS Engine开发入门教程
C#,ArcGIS Engine开发入门教程 转自:http://blog.csdn.net/yanleigis/article/details/2233674 目录(?)[+] 五实现 一 加载A ...
- ActiveMQ详细入门教程系列(一)
一.什么是消息中间件 两个系统或两个客户端之间进行消息传送,利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成.通过提供消息传递和消息排队模型,它可以在分布式环境下 ...
- WPF入门教程系列三——Application介绍(续)
接上文WPF入门教程系列二——Application介绍,我们继续来学习Application 三.WPF应用程序的关闭 WPF应用程序的关闭只有在应用程序的 Shutdown 方法被调用时,应用程序 ...
- WPF入门教程系列二——Application介绍
一.Application介绍 WPF和WinForm 很相似, WPF与WinForm一样有一个 Application对象来进行一些全局的行为和操作,并且每个 Domain (应用程序域)中仅且只 ...
- 一看就懂的Android APP开发入门教程
一看就懂的Android APP开发入门教程 作者: 字体:[增加 减小] 类型:转载 这篇文章主要介绍了Android APP开发入门教程,从SDK下载.开发环境搭建.代码编写.APP打包等步骤 ...
- iOS开发入门教程
iOS开发入门教程 http://my.oschina.net/mailzwj/blog/133273 摘要 iOS开发入门教程,从创建项目到运行项目,包括OC基础,调试,模拟器设置等相关知识. iO ...
随机推荐
- 图像处理|Matlab
图像处理 | Matlab 参考博文: 图像处理-平滑滤波 图像去噪-加性噪声(高斯/椒盐)
- 微信点击链接:debugx5.qq.com提示您使用的不是x5内核
微信点击链接:debugx5.qq.com提示您使用的不是x5内核 因为要测试小程序,需要webview调试功能,正常来说在微信任意一个聊天窗口,输入:debugx5.qq.com,点击该链接就可以, ...
- PageHeplper使用
1.引入POM 1 <dependency> 2 <groupId>com.github.pagehelper</groupId> 3 <artifactId ...
- JAVA设计模式及其设计原则
设计模式: 设计模式是一套被反复使用的.多数人知晓的.经过分类编目的.代码设计经验的总结. 单例模式:在一个jvm虚拟机,要创建的对象控制成独一份:举例:统计单台虚拟机内的用户在线数 package ...
- w10 端口转发
场景:同局域网,将其他电脑监听映射到本地.(由于各种安全设计的定点通信) 1.添加端口转发netsh interface portproxy add v4tov4 listenport=4000 li ...
- JS this指向相关
function Foo() { getName = function() { console.log(1) } return this;}Foo.getName = function() { con ...
- idea安装阿里规范审查插件
Install from repositories Settings >> Plugins >> Browse repositories... Search plugin by ...
- jQuery.extend 函数详解(转)
地址:http://www.jb51.net/article/29591.htm JQuery的extend扩展方法: Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些 ...
- 11. ASCII, unicode, utf-8, gbk的区别
这是几种编码方式 ASCII是包含英文字母数字特殊字符等, 长度是1字节, 前128个是基础ASCII码, 128个以后是扩展ASCII码 GBK是国标扩展码, 长度2字节, 表示汉字以及各少数民族语 ...
- 看看CabloyJS是如何异步加载并执行go wasm模块的
介绍 CabloyJS提供了一个内置模块a-wasmgo,将go wasm模块的异步加载运行机制进行了封装,使我们可以非常方便的在CabloyJS项目中引入go wasm,从而支持更多的业务场景开发 ...