构建网站

危险

本教程已过时。我们建议阅读 服务器框架 101

警告

创建一个基本模块

在 Odoo 中,任务通过创建模块来完成。

模块通过添加新功能或修改现有功能(包括其他模块添加的功能)来自定义 Odoo 安装的行为。

Odoo 的脚手架工具 可以设置一个基本模块。要快速开始,只需运行:

$ ./odoo-bin scaffold Academy my-modules

这将自动创建一个名为 my-modules模块目录,并在其中包含一个 academy 模块。如果需要,该目录可以是一个现有的模块目录,但模块名称在目录内必须唯一。

演示模块

我们有一个“完整”的模块,可以进行安装。

尽管它什么也不做,但我们仍然可以安装它:

  • 启动 Odoo 服务器

    $ ./odoo-bin --addons-path addons,my-modules
    
  • 访问 http://localhost:8069

  • 创建一个包含演示数据的新数据库

  • 前往 设置 ‣ 模块 ‣ 模块

  • 在右上角移除 已安装 过滤器,并搜索 academy

  • 点击 Academy 模块的 安装 按钮

切换到浏览器

控制器 解析浏览器请求并返回数据。

添加一个简单的控制器,并确保它被 __init__.py 导入(以便 Odoo 能找到它):

academy/controllers.py
# -*- coding: utf-8 -*-
from odoo import http

class Academy(http.Controller):

    @http.route('/academy/academy/', auth='public')
    def index(self, **kw):
        return "Hello, world"

关闭您的服务器(^C),然后重新启动:

$ ./odoo-bin --addons-path addons,my-modules

打开页面 http://localhost:8069/academy/academy/,您应该会看到您的“页面”出现:

../../_images/helloworld.png

模板

在 Python 中生成 HTML 并不令人愉快。

通常的解决方案是使用模板,即带有占位符和显示逻辑的伪文档。Odoo 支持任何 Python 模板系统,但提供了自己的 QWeb 模板系统,它可以与其他功能集成。

创建一个模板,并确保模板文件已在 __manifest__.py 清单中注册,然后修改控制器以使用我们的模板:

academy/controllers.py
class Academy(http.Controller):

    @http.route('/academy/academy/', auth='public')
    def index(self, **kw):
        return http.request.render('academy.index', {
            'teachers': ["Diana Padilla", "Jody Caroll", "Lester Vaughn"],
        })
academy/templates.xml
<odoo>

    <template id="index">
        <title>Academy</title>
        <t t-foreach="teachers" t-as="teacher">
            <p><t t-esc="teacher"/></p>
        </t>
    </template>

</odoo>

模板通过 t-foreach 遍历所有教师(通过 模板上下文 传递),并将每个教师打印在自己的段落中。

最后,重新启动 Odoo 并更新模块数据(以安装模板),方法是进入 设置 ‣ 模块 ‣ 模块 ‣ Academy,然后点击 升级

小技巧

或者,可以同时重新启动 Odoo 并更新模块:odoo-bin -u

$ odoo-bin --addons-path addons,my-modules -d academy -u academy

访问 http://localhost:8069/academy/academy/ 现在应该会得到以下结果:

../../_images/basic-list.png

在 Odoo 中存储数据

Odoo 模型 映射到数据库表。

在上一节中,我们只是显示了静态输入在 Python 代码中的一组字符串。这不允许修改或持久存储,因此我们现在将数据移到数据库中。

定义数据模型

定义一个教师模型,并确保从 __init__.py 导入它以便正确加载:

academy/models.py
from odoo import models, fields, api

class Teachers(models.Model):
    _name = 'academy.teachers'

    name = fields.Char()

然后为该模型设置 基本访问控制 并将其添加到清单文件中:

academy/__manifest__.py
# always loaded
'data': [
    'security/ir.model.access.csv',
    'templates.xml',
],
academy/security/ir.model.access.csv
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_academy_teachers,access_academy_teachers,model_academy_teachers,,1,0,0,0

这仅授予所有用户读取权限( perm_read )( group_id:id 留空)。

注解

数据文件 (XML 或 CSV)必须添加到模块清单中,Python 文件(模型或控制器)不需要,但必须从 __init__.py 直接或间接导入。

警告

管理员用户绕过访问控制,即使未被授予权限,他们也可以访问所有模型。

演示数据

第二步是向系统中添加一些演示数据,以便于测试。这是通过添加一个 demo 数据文件 完成的,该文件必须链接到清单文件中:

academy/demo.xml
<odoo>

    <record id="padilla" model="academy.teachers">
        <field name="name">Diana Padilla</field>
    </record>
    <record id="carroll" model="academy.teachers">
        <field name="name">Jody Carroll</field>
    </record>
    <record id="vaughn" model="academy.teachers">
        <field name="name">Lester Vaughn</field>
    </record>

</odoo>

小技巧

数据文件 可用于演示数据和非演示数据。演示数据仅在“演示模式”下加载,可用于流程测试和演示;非演示数据始终加载并用作系统的初始设置。

在这种情况下,我们使用演示数据,因为系统的实际用户可能希望输入或导入他们自己的教师列表,此列表仅用于测试。

访问数据

最后一步是修改模型和模板以使用我们的演示数据:

  1. 从数据库中获取记录,而不是使用静态列表

  2. 由于 search() 返回与过滤器匹配的记录集(此处为“所有记录”),请修改模板以打印每位教师的 name

academy/controllers.py
class Academy(http.Controller):

     @http.route('/academy/academy/', auth='public')
     def index(self, **kw):
         Teachers = http.request.env['academy.teachers']
         return http.request.render('academy.index', {
             'teachers': Teachers.search([])
         })
academy/templates.xml
<odoo>

    <template id="index">
         <title>Academy</title>
         <t t-foreach="teachers" t-as="teacher">
             <p><t t-esc="teacher.id"/> <t t-esc="teacher.name"/></p>
         </t>
    </template>

</odoo>

重新启动服务器并更新模块(以更新清单文件、模板并加载演示文件),然后导航至 http://localhost:8069/academy/academy/。页面应略有不同:名称前应简单地加上一个数字(教师的数据库标识符)。

网站支持

Odoo 提供了一个专门用于构建网站的模块。

到目前为止,我们已经比较直接地使用了控制器,但 Odoo 8 通过 website 模块增加了更深层次的集成以及一些其他服务(例如默认样式、主题)。

  1. 首先,将 website 添加为 academy 的依赖项。

  2. 然后在控制器上添加 website=True 标志,这会在 请求对象 上设置一些新变量,并允许在模板中使用网站布局。

  3. 在模板中使用网站布局

academy/__manifest__.py
'version': '0.1',

# any module necessary for this one to work correctly
'depends': ['website'],

# always loaded
'data': [
academy/controllers.py
class Academy(http.Controller):

     @http.route('/academy/academy/', auth='public', website=True)
     def index(self, **kw):
         Teachers = http.request.env['academy.teachers']
         return http.request.render('academy.index', {
             'teachers': Teachers.search([])
         })
academy/templates.xml
<odoo>

    <template id="index">
        <t t-call="website.layout">
            <t t-set="title">Academy</t>
            <div class="oe_structure">
                <div class="container">
                    <t t-foreach="teachers" t-as="teacher">
                        <p><t t-esc="teacher.id"/> <t t-esc="teacher.name"/></p>
                    </t>
                </div>
            </div>
        </t>
    </template>

</odoo>

在更新模块时重启服务器(以更新清单和模板),访问 http://localhost:8069/academy/academy/ 应该会显示一个更美观的页面,包含品牌标识和许多内置的页面元素(顶级菜单、页脚等)。

../../_images/layout.png

网站布局还提供了对编辑工具的支持:点击右上角的 登录 ,输入凭据(默认为 admin / admin ),然后点击 登录

现在您已进入 Odoo 的“正式”界面:管理界面。目前请点击左上角的 网站 菜单项。

我们又回到了网站,但现在是作为管理员,可以使用 网站 支持提供的高级编辑功能:

  • 模板代码编辑器(自定义 ‣ HTML 编辑器),您可以在其中查看和编辑当前页面使用的所有模板。

  • 左上角的 编辑 按钮切换到“编辑模式”,在此模式下可以使用区块(片段)和富文本编辑功能。

  • 还有许多其他功能,例如移动预览或 SEO(搜索引擎优化)

URL 和路由

控制器方法通过 route() 装饰器与 路由 关联,该装饰器接受一个路由字符串和若干属性以自定义其行为或安全性。

我们已经看到了一个“字面量”路由字符串,它完全匹配 URL 部分,但路由字符串还可以使用 转换模式,它们匹配 URL 的部分并将其作为局部变量提供。例如,我们可以创建一个新的控制器方法,接收一部分 URL 并将其打印出来:

academy/controllers.py
# New route
@http.route('/academy/<name>/', auth='public', website=True)
def teacher(self, name):
    return '<h1>{}</h1>'.format(name)

重启 Odoo,访问 http://localhost:8069/academy/Alice/http://localhost:8069/academy/Bob/,并观察差异。

顾名思义,转换模式 不仅进行提取,还会执行 验证转换,因此我们可以更改新的控制器以仅接受整数:

academy/controllers.py
@http.route('/academy/<int:id>/', auth='public', website=True)
def teacher(self, id):
    return '<h1>{} ({})</h1>'.format(id, type(id).__name__)

重启 Odoo,访问 http://localhost:8069/academy/2,注意旧值是一个字符串,而新值被转换为整数。尝试访问 http://localhost:8069/academy/Carol/,并注意页面未找到:因为 “Carol” 不是整数,路由被忽略且未找到任何路由。

Odoo 提供了一个名为 model 的附加转换器,当给定记录 ID 时,它会直接提供记录。让我们使用它来为教师传记创建一个通用页面:

academy/controllers.py
@http.route('/academy/<model("academy.teachers"):teacher>/', auth='public', website=True)
def teacher(self, teacher):
    return http.request.render('academy.biography', {
        'person': teacher
    })
academy/templates.xml
<template id="biography">
    <t t-call="website.layout">
        <t t-set="title">Academy</t>
        <div class="oe_structure"/>
        <div class="oe_structure">
            <div class="container">
                <h3><t t-esc="person.name"/></h3>
            </div>
        </div>
        <div class="oe_structure"/>
    </t>
</template>

然后更改模型列表以链接到我们的新控制器:

academy/templates.xml
<template id="index">
    <t t-call="website.layout">
        <t t-set="title">Academy</t>
        <div class="oe_structure">
            <div class="container">
                <t t-foreach="teachers" t-as="teacher">
                    <p>
                        <a t-attf-href="/academy/{{ slug(teacher) }}">
                        <t t-esc="teacher.name"/></a>
                    </p>
                </t>
            </div>
        </div>
    </t>
</template>

重启 Odoo 并升级模块,然后您可以访问每位教师的页面。作为一个练习,尝试在某位教师的页面上添加区块以撰写传记,然后转到另一位教师的页面,依此类推。您会发现,您的传记在所有教师之间共享,因为区块被添加到了 模板 中,而 传记 模板在所有教师之间共享,当一个页面被编辑时,所有页面都会同时被编辑。

字段编辑

特定于记录的数据应保存在该记录上,因此让我们为教师添加一个新的传记字段:

academy/models.py
class Teachers(models.Model):
    _name = 'academy.teachers'

    name = fields.Char()
    biography = fields.Html()
academy/templates.xml
<template id="biography">
    <t t-call="website.layout">
        <t t-set="title">Academy</t>
        <div class="oe_structure"/>
        <div class="oe_structure">
            <div class="container">
                <h3><t t-esc="person.name"/></h3>
                <div><t t-esc="person.biography"/></div>
            </div>
        </div>
        <div class="oe_structure"/>
    </t>
</template>

重启 Odoo 并更新视图,重新加载教师页面……由于字段为空,因此它是不可见的。

对于记录字段,模板可以使用特殊的 t-field 指令,该指令允许通过字段特定的界面从网站编辑字段内容。将 person 模板更改为使用 t-field

academy/templates.xml
<div class="oe_structure">
    <div class="container">
        <h3 t-field="person.name"/>
        <div t-field="person.biography"/>
    </div>
</div>

重新启动 Odoo 并升级模块后,教师名称下方会出现一个占位符,并且在 编辑 模式下会有一个新的区块区域。放置在那里的内容将存储在相应教师的 biography 字段中,因此是特定于该教师的。

教师的姓名也是可编辑的,保存后更改将在索引页面上可见。

t-field 还可以接受取决于具体字段的格式化选项。例如,如果我们显示教师记录的修改日期:

academy/templates.xml
<div class="oe_structure">
    <div class="container">
        <h3 t-field="person.name"/>
        <p>Last modified: <i t-field="person.write_date"/></p>
        <div t-field="person.biography"/>
    </div>
</div>

它以一种非常“计算机化”的方式显示,难以阅读,但我们可以要求一个人类可读的版本:

academy/templates.xml
<div class="oe_structure">
    <div class="container">
        <h3 t-field="person.name"/>
        <p>Last modified: <i t-field="person.write_date" t-options='{"format": "long"}'/></p>
        <div t-field="person.biography"/>
    </div>
</div>

或相对显示:

academy/templates.xml
<div class="oe_structure">
    <div class="container">
        <h3 t-field="person.name"/>
        <p>Last modified: <i t-field="person.write_date" t-options='{"widget": "relative"}'/></p>
        <div t-field="person.biography"/>
    </div>
</div>

管理与ERP集成

Odoo 管理功能的简要且不完整的介绍

网站支持 部分曾简单介绍过 Odoo 的管理功能。我们可以通过菜单中的 管理员 ‣ 管理员 返回(如果已登出,则使用 登录 )。

Odoo 后端的概念结构很简单:

  1. 首先是菜单,一个记录的树状结构(菜单可以有子菜单)。没有子菜单的菜单映射到……

  2. 动作。动作有多种类型:链接、报告、Odoo 应执行的代码或数据展示。数据展示动作称为 窗口动作,它们告诉 Odoo 根据一组视图显示指定的 模型……

  3. 视图具有类型,即其对应的大类(列表、图表、日历)以及用于自定义模型在视图中显示方式的 架构

在 Odoo 管理后台中编辑

默认情况下,Odoo 模型对用户来说基本上是不可见的。为了使其可见,它必须通过某个动作可用,而该动作本身需要可通过菜单访问。

让我们为我们的模型创建一个菜单:

academy/__manifest__.py
# always loaded
'data': [
    'security/ir.model.access.csv',
    'templates.xml',
    'views.xml',
],
academy/views.xml
<odoo>
    <record id="action_academy_teachers" model="ir.actions.act_window">
        <field name="name">Academy teachers</field>
        <field name="res_model">academy.teachers</field>
    </record>

    <menuitem sequence="0" id="menu_academy" name="Academy"/>
    <menuitem id="menu_academy_content" parent="menu_academy"
                name="Academy Content"/>
    <menuitem id="menu_academy_content_teachers"
                parent="menu_academy_content"
                action="action_academy_teachers"/>
</odoo>

然后访问 http://localhost:8069/web/,左上角应该会出现一个菜单 学院 ,默认选中,因为它是第一个菜单,并且会打开教师列表。从列表中可以 创建 新的教师记录,并切换到按记录的“表单”视图。

如果没有定义如何展示记录( 视图 ),Odoo 会自动即时创建一个基本的视图。在我们的例子中,目前“列表”视图可以正常工作(仅显示教师姓名),但在“表单”视图中,HTML biography 字段与 name 字段并排显示,且空间不足。让我们定义一个自定义表单视图,以改善查看和编辑教师记录的体验:

academy/views.xml
<record id="academy_teacher_form" model="ir.ui.view">
    <field name="name">Academy teachers: form</field>
    <field name="model">academy.teachers</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <field name="name"/>
                <field name="biography"/>
            </sheet>
        </form>
    </field>
</record>

模型之间的关系

我们已经看到了直接存储在记录中的一对“基本”字段。还有 许多基本字段 。字段的第二大类是 关系字段 ,用于将记录相互链接(在同一模型内或跨模型)。

为了演示,让我们创建一个 课程 模型。每门课程应有一个 teacher 字段,链接到单个教师记录,但每位教师可以教授多门课程:

academy/models.py
class Courses(models.Model):
    _name = 'academy.courses'

    name = fields.Char()
    teacher_id = fields.Many2one('academy.teachers', string="Teacher")
academy/security/ir.model.access.csv
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_academy_teachers,access_academy_teachers,model_academy_teachers,,1,0,0,0
access_academy_courses,access_academy_courses,model_academy_courses,,1,0,0,0

让我们也添加视图,以便查看和编辑课程的教师:

academy/views.xml
<record id="action_academy_courses" model="ir.actions.act_window">
    <field name="name">Academy courses</field>
    <field name="res_model">academy.courses</field>
</record>
<record id="academy_course_search" model="ir.ui.view">
    <field name="name">Academy courses: search</field>
    <field name="model">academy.courses</field>
    <field name="arch" type="xml">
        <search>
            <field name="name"/>
            <field name="teacher_id"/>
        </search>
    </field>
</record>
<record id="academy_course_list" model="ir.ui.view">
    <field name="name">Academy courses: list</field>
    <field name="model">academy.courses</field>
    <field name="arch" type="xml">
        <list string="Courses">
            <field name="name"/>
            <field name="teacher_id"/>
        </list>
    </field>
</record>
<record id="academy_course_form" model="ir.ui.view">
    <field name="name">Academy courses: form</field>
    <field name="model">academy.courses</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <field name="name"/>
                <field name="teacher_id"/>
            </sheet>
        </form>
    </field>
</record>

<menuitem sequence="0" id="menu_academy" name="Academy"/>
<menuitem id="menu_academy_content" parent="menu_academy"
            name="Academy Content"/>
<menuitem id="menu_academy_content_courses"
            parent="menu_academy_content"
            action="action_academy_courses"/>
<menuitem id="menu_academy_content_teachers"
            parent="menu_academy_content"
            action="action_academy_teachers"/>

还应该可以从教师页面直接创建新课程,或者查看他们教授的所有课程,因此需要在 教师 模型中添加 反向关系

academy/models.py
class Teachers(models.Model):
    _name = 'academy.teachers'

    name = fields.Char()
    biography = fields.Html()

    course_ids = fields.One2many('academy.courses', 'teacher_id', string="Courses")

class Courses(models.Model):
    _name = 'academy.courses'

    name = fields.Char()
    teacher_id = fields.Many2one('academy.teachers', string="Teacher")
academy/views.xml
<record id="academy_teacher_form" model="ir.ui.view">
    <field name="name">Academy teachers: form</field>
    <field name="model">academy.teachers</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <field name="name"/>
                <field name="biography"/>
                <field name="course_ids">
                    <list string="Courses" editable="bottom">
                        <field name="name"/>
                    </list>
                </field>
            </sheet>
        </form>
    </field>
</record>

讨论与通知

Odoo 提供了一些技术模型,它们虽然不直接满足业务需求,但可以为业务对象添加功能,而无需手动构建。

其中之一是 Chatter 系统,它是 Odoo 电子邮件和消息系统的一部分,可以为任何模型添加通知和讨论线程。模型只需 _inherit mail.thread,并在其表单视图中添加 message_ids 字段即可显示讨论线程。讨论线程是基于每条记录的。

对于我们的学院来说,允许对课程进行讨论以处理例如时间表变更或教师与助教之间的讨论是有意义的:

academy/__manifest__.py
'version': '0.1',

# any module necessary for this one to work correctly
'depends': ['website', 'mail'],

# always loaded
'data': [
academy/models.py
class Courses(models.Model):
    _name = 'academy.courses'
    _inherit = 'mail.thread'

    name = fields.Char()
    teacher_id = fields.Many2one('academy.teachers', string="Teacher")
academy/views.xml
<record id="academy_course_form" model="ir.ui.view">
    <field name="name">Academy courses: form</field>
    <field name="model">academy.courses</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <field name="name"/>
                <field name="teacher_id"/>
            </sheet>
            <div class="oe_chatter">
                <field name="message_follower_ids" widget="mail_followers"/>
                <field name="message_ids" widget="mail_thread"/>
            </div>
        </form>
    </field>
</record>

在每个课程表单的底部,现在有一个讨论线程,并且系统用户可以留下消息以及关注或取消关注与特定课程相关的讨论。

销售课程

Odoo 还提供了一些业务模型,可以直接满足或选择加入业务需求。例如,website_sale 模块基于 Odoo 系统中的产品设置了一个电子商务站点。我们可以通过将课程定义为特定类型的产品,轻松实现课程订阅的销售。

这并不是传统的继承方式,而是意味着用 产品 模型替换我们的 课程 模型,并在原地扩展产品(以添加我们需要的内容)。

首先,我们需要添加对 website_sale 的依赖,以便同时获得产品(通过 sale)和电子商务界面:

academy/__manifest__.py
'version': '0.1',

# any module necessary for this one to work correctly
'depends': ['mail', 'website_sale'],

# always loaded
'data': [

重新启动 Odoo 并更新您的模块后,网站上现在会出现一个 商店 部分,其中列出了许多预填充(通过演示数据)的产品。

第二步是用 product.template 替换 课程 模型,并为课程添加一个新的产品类别:

academy/__manifest__.py
    'security/ir.model.access.csv',
    'templates.xml',
    'views.xml',
    'data.xml',
],
# only loaded in demonstration mode
'demo': [
academy/data.xml
<odoo>
    <record model="product.public.category" id="category_courses">
        <field name="name">Courses</field>
        <field name="parent_id" ref="website_sale.categ_others"/>
    </record>
</odoo>
academy/demo.xml
<record id="course0" model="product.template">
    <field name="name">Course 0</field>
    <field name="teacher_id" ref="padilla"/>
    <field name="public_categ_ids" eval="[(4, ref('academy.category_courses'), False)]"/>
    <field name="website_published">True</field>
    <field name="list_price" type="float">0</field>
    <field name="type">service</field>
</record>
<record id="course1" model="product.template">
    <field name="name">Course 1</field>
    <field name="teacher_id" ref="padilla"/>
    <field name="public_categ_ids" eval="[(4, ref('academy.category_courses'), False)]"/>
    <field name="website_published">True</field>
    <field name="list_price" type="float">0</field>
    <field name="type">service</field>
</record>
<record id="course2" model="product.template">
    <field name="name">Course 2</field>
    <field name="teacher_id" ref="vaughn"/>
    <field name="public_categ_ids" eval="[(4, ref('academy.category_courses'), False)]"/>
    <field name="website_published">True</field>
    <field name="list_price" type="float">0</field>
    <field name="type">service</field>
</record>
academy/models.py
class Courses(models.Model):
    _name = 'academy.courses'
    _inherit = ['mail.thread', 'product.template']

    name = fields.Char()
    teacher_id = fields.Many2one('academy.teachers', string="Teacher")

安装完成后,一些课程现在可以在 商店 中找到,尽管可能需要搜索一下。

注解

  • 要在原地扩展模型,使用 继承 而不赋予它新的 _name

  • product.template 已经使用了讨论系统,因此我们可以将其从扩展模型中移除。

  • 我们将课程默认创建为 已发布 状态,这样无需登录即可查看。

修改现有视图

到目前为止,我们已经简要了解了:

  • 新模型的创建

  • 新视图的创建

  • 新记录的创建

  • 现有模型的修改

剩下的就是现有记录的修改和现有视图的修改。我们将在 商店 页面上同时完成这两项任务。

视图修改是通过创建 扩展 视图来完成的,这些视图应用在原始视图之上并对其进行修改。这些修改视图可以添加或移除,而无需修改原始视图,从而更容易尝试和回滚更改。

由于我们的课程是免费的,因此没有理由在商店页面上显示价格,因此我们将修改视图并在价格为 0 时隐藏它。第一项任务是找出哪个视图显示了价格,这可以通过 自定义 ‣ HTML 编辑器 完成,它允许我们查看参与页面渲染的各种模板。浏览其中几个模板后,“产品项目”看起来是一个可能的目标。

修改视图架构分为三个步骤:

  1. 创建一个新视图

  2. 通过将新视图的 inherit_id 设置为被修改视图的外部 ID 来扩展视图

  3. 在架构中,使用 xpath 标签选择并修改来自被修改视图的元素

academy/templates.xml
 <template id="product_item_hide_no_price" inherit_id="website_sale.products_item">
     <xpath expr="//div[hasclass('product_price')]/b" position="attributes">
         <attribute name="t-if">product.price &gt; 0</attribute>
     </xpath>
 </template>

我们要修改的第二件事是让产品分类侧边栏默认可见:自定义 ‣ 产品分类 允许您打开或关闭一个用于过滤主显示的产品分类树。

这是通过扩展模板的 customize_showactive 字段完成的:一个扩展模板(例如我们刚刚创建的那个)可以设置为 customize_show=True。此选项会在 自定义 菜单中显示该视图,并附带一个复选框,允许管理员激活或禁用它们(从而轻松自定义其网站页面)。

我们只需修改 产品分类 记录并将其默认值设置为 active=”True”

academy/templates.xml
<record id="website_sale.products_categories" model="ir.ui.view">
    <field name="active" eval="True"/>
</record>

这样,在安装 学院 模块时,产品分类 侧边栏将自动启用。