第5章:最后,一些UI可以玩

第5章:最后,一些UI可以玩

现在我们已经创建了新模型及其相应的访问权限,现在是时候与用户界面交互。

在本章的结尾,我们将创建几个菜单以访问默认列表和表单视图。

在第4章:安全性-简介中,我们通过CSV文件添加了数据。在要加载的数据格式简单时CSV很方便。当格式更复杂时(例如,加载视图或电子邮件模板的结构),我们使用XML格式。例如 此帮助字段包含 HTML 标记。虽然可以通过 CSV 文件加载此类数据,但它使用 XML文件比CSV文件方便。

        <field name="help" type="html">

          <p class="o_view_nocontent_smiling_face">

            Define a new lost reason

          </p><p>

            Use lost reasons to explain why an opportunity is lost.

          </p><p>

            Some examples of lost reasons: "We don't have people/skill", "Price too high"

          </p>

        </field>

XML 文件必须添加到与 CSV 文件相同的文件夹中,并在__manifest__.py数据文件的内容也会在安装模块时按顺序加载,因此对 CSV 文件所做的所有注释都适用于 XML 文件。当数据链接到视图时,我们会将它们添加到views文件夹中。

所以,我们的模块结构如下:

 

在本章中,我们将通过XML文件加载第一个操作和菜单。操作和菜单是数据库中的标准记录。

在Odoo中,用户界面(动作、菜单和视图)主要通过创建以及编写XML文件中定义的记录。一种常见模式是菜单 >动作 > 视图。要访问记录,用户需要浏览多个菜单级别;最深的层级是触发打开记录列表的动作。

 

动作(action)可以通过三种方式触发操作:

  1. 通过单击菜单项(链接到特定操作)
  2. 通过单击视图中的按钮(如果这些按钮连接到操作)
  3. 作为对象上的上下文操作

 

在本章中,我们只介绍第一种情况。第二种情况将在后面的章节中介绍,而最后一种情况是 高级主题的重点。在我们的Estate示例中,我们希望将菜单链接到estate.property模型,以便我们能够创建新记录。该操作可以被视为菜单和模型之间的链接。

以下代码是我们的test_model一个最基本动作:

<record id="test_model_action" model="ir.actions.act_window">

    <field name="name">Test action</field>

    <field name="res_model">test_model</field>

    <field name="view_mode">list,form</field>

</record>

 

id是外部标识符。它可以用来引用记录 (不知道其数据库内标识符)。

model具有固定值ir.actions.act_window(窗口操作(ir.actions.act_window))。

name是操作的名称。

res_model是操作适用的模型。

view_mode是将可用的视图;在本例中,它们是List和Form视图。我们稍后会看到,还可以有其他的视图模式。

 

下面的代码是简单操作的一个很好的示例。请注意XML数据文件的结构,因为您将在下面的练习中需要它。

    <record id="crm_lost_reason_action" model="ir.actions.act_window">

        <field name="name">Lost Reasons</field>

        <field name="res_model">crm.lost.reason</field>

        <field name="view_mode">tree,form</field>

        <field name="help" type="html">

          <p class="o_view_nocontent_smiling_face">

            Define a new lost reason

          </p><p>

            Use lost reasons to explain why an opportunity is lost.

          </p><p>

            Some examples of lost reasons: "We don't have people/skill", "Price too high"

          </p>

        </field>

</record>

 

为我们的esteta模块创建以下文件views/estate_property_views.xml

<?xml version="1.0"?>

<odoo>

    <record id="estate_property_action" model="ir.actions.act_window">

        <field name="name">estate action</field>

        <field name="res_model">estate_property</field>

        <field name="view_mode">tree, form</field>

    </record>

</odoo>

并在__manifest__.py文件中定义它:

{

    'name': 'Real Estate',

    'version': '1.0',

    'description': 'Real Estate',

    'data': [

        'security/ir.model.access.csv',

        'views/estate_property_views.xml',

    ]

}

重新启动服务器,您应该会看到文件加载到日志中。

INFO odoo odoo.modules.loading: loading estate/views/estate_property_views.xml

 

为了减少声明菜单(ir.ui.menu)并将其连接到相应操作的复杂性,我们可以使用 <menuitem> 快捷方式。

举个test_model_action例子,我们的基本菜单是:

<menuitem id="test_model_menu_action" action="test_model_action"/>

菜单test_model_menu_action将链接到动作test_model_action,而操作链接到模型test_model 。如前所述,该动作可以看作是链接在菜单和模型之间。

 

但是,菜单始终遵循体系结构,实际上有三个级别的菜单:

1、根菜单,显示在 应用程序切换器 (Odoo社区应用程序切换器是一个下拉菜单)

2、一级菜单,显示在顶部栏中

3、操作菜单

以下图片展示了3个菜单:

 

定义结构的最简单方法是在XML文件中创建它。test_model_action一个基本的结构:

<menuitem id="test_menu_root" name="Test">

    <menuitem id="test_first_level_menu" name="First Level">

        <menuitem id="test_model_menu_action" action="test_model_action"/>

    </menuitem>

</menuitem>

第三个菜单的名称取自action。

 

下面为我们的estate.property动作创建3层菜单

创建以下文件views/estate_menus.xml:

<?xml version="1.0" encoding="utf-8"?>

<odoo>

    <menuitem id="estate_property_menu_root" name="Real Estate">

        <menuitem id="real_restate_advertisements_menu" name="Advertisements">

            <menuitem id="estate_property_menu_action" action="estate_property_action"/>

        </menuitem>

    </menuitem>

</odoo>

记得在manifest.py中定义它。

然后修改views/estate_property_views.xml为:

<?xml version="1.0"?>

<odoo>

    <record id="estate_property_action" model="ir.actions.act_window">

        <field name="name">房屋</field>

        <field name="res_model">estate_property</field>

        <field name="view_mode">tree,form</field>

    </record>

</odoo>

 

重新启动服务器并刷新浏览器,您现在应该看到菜单,您甚至可以创建您的第一个房地产广告!以下是效果:

 

我们现在的模型代码是这样的:

class EstateProperty(models.Model):

    _name = "estate_property"

    _description = "Estate Property"

    name = fields.Char(required=True)

    description = fields.Text()

    postcode = fields.Char()

    date_available = fields.Date()

    expected_price = fields.Float(required=True)

    selling_price = fields.Float()

    bedrooms = fields.Integer()

    living_area = fields.Integer()

    facades = fields.Integer()

    garage = fields.Boolean()

    garden = fields.Boolean()

    garden_area = fields.Integer()

    garden_orientation = fields.Selection([

        ("north", "North"),

        ("south", "South"),

        ("east", "East"),

        ("west", "West"),

    ])

    active = fields.Boolean(default=True)

    state = fields.Selection([

        ("new", "New"),

        ("offer_received", "Offer Received"),

        ("offer_accepted", "Offer Accepted"),

        ("sold", "Sold"),

        ("canceled", "Canceled"),

], default="new",copy=False)

 

到目前为止,我们只在房地产广告中使用了通用视图,但是在大多数情况下,我们希望微调视图。Odoo中有许多微调,通常,第一步是确保:

1、某些字段具有默认值

2、某些字段是只读的

3、复制记录时不会复制某些字段

在我们的房地产商业案例中,我们希望以下内容:

1、销售价格应该是只读的(稍后会自动填写)

2、复制记录时,不应复制可用日期和销售价格

3、默认卧室数应为2

4、默认可用性日期应为3个月

 

在进一步进行视图设计之前,让我们先回到模型定义。我们看到,一些属性(如 required=True)会影响数据库中的表模式。

 

接下来,我们向字段添加新属性。

将 Selling price(销售价格)设置为read-only(只读)

防止复制date_available和selling_price的值

date_available = fields.Date(copy=False)

selling_price = fields.Float(readonly=True, copy=False)

重新启动服务器并刷新浏览器。您应该无法设置任何销售价格。

 

可以为任何字段指定默认值。在字段定义中,添加default=X选项,其中X是 Python 文本值(boolean、integer、 float, string) 或获取模型并返回值的函数:

name = fields.Char(default="Unknown")

last_seen = fields.Datetime("Last Seen", default=fields.Datetime.now)

默认情况下,name字段的值为“Unknown”,而last_seen字段默认值为当前时间。

 

接下来给我们的模型设置默认值。

添加适当的默认属性,以便:

默认卧室数量为 2

默认可用日期为 3 个月后

代码如下:

from odoo import models, fields, api

from dateutil.relativedelta import relativedelta

 

class EstateProperty(models.Model):

    _name = "estate_property"

    _description = "Estate Property"

 

    def _get_default_date_available(self):

        # 使用 fields.Date.today() 获取当前日期,并添加三个月

        return fields.Date.today() + relativedelta(months=+3)

    name = fields.Char(required=True, default="Unknown")

    description = fields.Text()

    postcode = fields.Char()

    date_available = fields.Date(copy=False, default=_get_default_date_available)

    expected_price = fields.Float(required=True)

    selling_price = fields.Float(readonly=True, copy=False)

    bedrooms = fields.Integer()

    living_area = fields.Integer()

    facades = fields.Integer()

    garage = fields.Boolean()

    garden = fields.Boolean()

    garden_area = fields.Integer()

    garden_orientation = fields.Selection([

        ("north", "North"),

        ("south", "South"),

        ("east", "East"),

        ("west", "West"),

    ])

    active = fields.Boolean(default=True)

    state = fields.Selection([

        ("new", "New"),

        ("offer_received", "Offer Received"),

        ("offer_accepted", "Offer Accepted"),

        ("sold", "Sold"),

        ("canceled", "Canceled"),

    ], default="new")

 

一些字段名称是为预定义行为保留的。当需要相关行为时,应在模型上定义它们。

我们已经将active和state字段添加到estate.property模型中,当把active设置成false时,默认的房屋列表中将不会显示active=false的房屋。

active是保留字段,具有特定行为:当记录active=False时,它将自动从任何搜索中移除。要显示创建的属性,需要专门搜索非活动记录。

第5章:最后,一些UI可以玩
谢潮聪 2024年12月3日
分析这篇文章

存档
登录 留下评论
第4章:安全性-简介