15158846557 在线咨询 在线咨询
15158846557 在线咨询
所在位置: 首页 > 营销资讯 > 网站运营 > Odoo11.0官方开发文档-教程-网站的构建

Odoo11.0官方开发文档-教程-网站的构建

时间:2023-08-05 11:27:02 | 来源:网站运营

时间:2023-08-05 11:27:02 来源:网站运营

Odoo11.0官方开发文档-教程-网站的构建:创建一个基本模块

在Odoo中,任务通过创建模块来执行。

模块定制了Odoo安装的行为,可通过添加新行为或者更改现有的行为来实现(包括通过其他模块添加的行为)。

Odoo的scaffold可以创建一个基本的模块,要快速开始只需简单的调用:

$ ./odoo-bin scaffold Academy my-modules这样会自动创建一个my-modules模块目录以及一个内部的academy 模块。该目录可以是一个您希望的已存在的模块目录。但是模块名称在目录中必须是唯一的。

演示模块

我们有了一个“完整”的待安装的模块。

虽然里面什么都没有,但是我们也可以安装它:

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

对于浏览器

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

添加一个简单的控制器并确保它在__init__.py 中导入(以便Odoo可以识别):

academy/controllers.py

# -*- coding: utf-8 -*-from odoo import httpclass Academy(http.Controller): @http.route('/academy/academy/', auth='public') def index(self, **kw): return "Hello, world"# @http.route('/academy/academy/objects/', auth='public')# def list(self, **kw):停止您的服务 (^C) 并重启它:

$ ./odoo-bin --addons-path addons,my-modules打开页面:http://localhost:8069/academy/academy/,您应该看到网页显示:







模板

在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"], })# @http.route('/academy/academy/objects/', auth='public')# def list(self, **kw):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> <!-- <template id="object"> --> <!-- <h1><t t-esc="object.display_name"/></h1> --> <!-- <dl> -->模板按所有教员迭代 (t-foreach) (通过模板上下文),并在它自己的段落中打印每个教员。

最后重启Odoo并转到设置>模块>模块>Academy,点击升级更新模块的数据(安装模板)。

另外,也可以重启Odoo并同时更新模块:

$ odoo-bin --addons-path addons,my-modules -d academy -u academy现在转到http://localhost:8069/academy/academy/ 可以看到:







在Odoo中保存数据

Odoo模型映射到数据库的表格中。

在前面一个章节中,我们刚刚显示了在Python代码中输入的一个静态列表。但这样无法修改或者持久性的保存,因此我们现在把数据移到数据库中。

定义数据模型

定义一个教员模型,并确保它从__init__.py 正确导入:

academy/models.py

from odoo import models, fields, apiclass Teachers(models.Model): _name = 'academy.teachers' name = fields.Char()然后为模型设置基本的访问控制并把它们添加到清单文件:

academy/__manifest__.py

# always loaded 'data': [ 'security/ir.model.access.csv', 'templates.xml', ], # only loaded in demonstration modeacademy/security/ir.model.access.csv

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlinkaccess_academy_teachers,access_academy_teachers,model_academy_teachers,,1,0,0,0这样就简单的把读取的权限 (perm_read) 开给了所有用户(group_id:id 留空)。

数据文件(XML或者CSV)必须添加到模块的清单文件中,而Python文件(models或者controllers)则需要在__init__.py 文件中导入(直接或者间接)

警告

管理员用户会绕过访问控制,它们拥有对所有模型的访问权,即时没有分配相应的访问权限

演示数据

第二步是添加一些演示数据到系统中以方便测试。这可以通过添加演示数据文件来完成,它必须在清单文件中引用:

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([]) })# @http.route('/academy/academy/objects/', auth='public')academy/templates.xml

<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> <!-- <template id="object"> -->重启服务并更新模块(目的是更新清单文件和模板并载入演示文件)然后浏览:http://localhost:8069/academy/academy/。页面看起来会稍有不同:名称会简单的以数字作为前缀(教员在数据库中的标识)。

网站支持

Odoo打包了一个专用于构建网站的模块。

现在我们很直接的使用了控制器,但Odoo 8 通过website 模块添加了更深度的集成和一些其他的服务(例如默认风格、主题)。

  1. 首先,添加website 作为academy 的依赖
  2. 然后在控制器中添加website=True 标志,这样会在请求对象上设置一些新的变量,并允许在我们的模板中使用website布局
  3. 在模板中使用website布局
academy/__manifest__.py

'version': '0.1', # any module necessary for this one to work correctly 'depends': ['website'], # always loaded 'data': [academy/controllers.py

from odoo import httpclass 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', {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> <!-- <template id="object"> -->重启服务并更新模块(为了更新清单文件和模板),访问http://localhost:8069/academy/academy/ 会得到一个更好看的页面,带有品牌和一些内建的页面元素(顶级菜单,页脚……等等)







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

您已正确的进入了Odoo的管理界面。现在点击左上角的网站菜单。

我们以管理员身份再次回到网站前端,现在具有了website模块提供的高级的功能:

URL和路由

控制器方法通过route()装饰器与路由关联,它使用一个路由字符串和一组属性来自定义行为或安全。

我们已经见过了“文本型”的路由字符串,它精确的匹配一个URL区块,但路由字符串也可以使用匹配URL字位并将变量转换为本地变量的转换器模式。例如,我们可以创建一个新的控制器方法,它使用一个URL字位并将它打印出来:

academy/controllers.py

'teachers': Teachers.search([]) }) @http.route('/academy/<name>/', auth='public', website=True) def teacher(self, name): return '<h1>{}</h1>'.format(name)# @http.route('/academy/academy/objects/', auth='public')# def list(self, **kw):# return http.request.render('academy.listing', {重启Odoo,访问http://localhost:8069/academy/Alice/http://localhost:8069/academy/Bob/ 查看差异。

和名称表示的一样,转换器模式不只是做抽取,它们也做验证转换,因此我们可以把新控制器改为只接受整形参数:

academy/controllers.py

'teachers': Teachers.search([]) }) @http.route('/academy/<int:id>/', auth='public', website=True) def teacher(self, id): return '<h1>{} ({})</h1>'.format(id, type(id).__name__)# @http.route('/academy/academy/objects/', auth='public')重启Odoo,访问http://localhost:8069/academy/2,注意虽然旧值是一个字符串,但新的值已经被转换成一个整数。请访问http://localhost:8069/academy/Carol/ 请注意该页面是找不到的:因为“Carol”不是一个整形,路由被忽略,找不到对应的值。

Odoo提供了一个额外的转换器名为model,它在给定ID时直接提供记录。让我们利用这个来为教员的传记(biography)创建一个常规的页面:

academy/controllers.py

'teachers': Teachers.search([]) }) @http.route('/academy/<model("academy.teachers"):teacher>/', auth='public', website=True) def teacher(self, teacher): return http.request.render('academy.biography', { 'person': teacher })# @http.route('/academy/academy/objects/', auth='public')academy/templates.xml

</div> </t> </template> <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"> <p><t t-esc="person.id"/> <t t-esc="person.name"/></p> </div> </div> <div class="oe_structure"/> </t> </template> <!-- <template id="object"> --> <!-- <h1><t t-esc="object.display_name"/></h1> --> <!-- <dl> -->然后修改模型列表来关联到我们的新控制器:

academy/templates.xml

<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> <div class="oe_structure"/> <div class="oe_structure"> <div class="container"> <h3><t t-esc="person.name"/></h3> </div> </div> <div class="oe_structure"/>重启Odoo并升级模块,然后您可以访问到每个教员的页面。作为练习,添加一些区块到教员的页面来撰写一个传记,然后转到另外一个教员的页面做相同的操作。您会发现,您的传记在所有教员之间共享了,因为这些区块被添加到了模板中,而传记模板在所有教员中共享,因此其中一个页面被编辑后,它们都同时被修改了。

字段编辑

指定记录的数据应该被保存在该记录上,我们来添加一个传记字段(biography)到教员中:

academy/models.py

_name = 'academy.teachers' name = fields.Char() biography = fields.Html()academy/templates.xml

<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"/>重启Odoo并更新视图,刷新教员页面……因为字段是空的所以并不可见。

对于记录的字段,模板可以使用一个特殊的t-field 指示,它允许使用指定字段的界面从网站编辑字段内容。修改模板person来使用t-field

academy/templates.xml

<div class="oe_structure"/> <div class="oe_structure"> <div class="container"> <h3 t-field="person.name"/> <div t-field="person.biography"/> </div> </div> <div class="oe_structure"/>重启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

'data': [ 'security/ir.model.access.csv', 'templates.xml', 'views.xml', ], # only loaded in demonstration mode 'demo': [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"/>然后在左上角菜单中的Academy菜单访问http://localhost:8069/web/,它默认作为第一个菜单被选中,打开一个教员的列表。从列表中可以创建一条教员的记录,并通过记录视图切换到“表单”。

如果没有如何显示记录(视图)的定义,Odoo会自动实时创建一个基本的定义。在我们的案例中,它现在对于“列表”视图可用(仅显示教员的名称),但“表单”视图中HTML字段biography会在name字段旁边显示,并且没有足够的空间。让我们定义一个自定义的表单视图,来获得更好的查看和编辑教员记录的体验:

academy/views.xml

<field name="res_model">academy.teachers</field> </record> <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> <label for="name"/> <field name="name"/> <label for="biography"/> <field name="biography"/> </sheet> </form> </field> </record> <menuitem sequence="0" id="menu_academy" name="Academy"/> <menuitem id="menu_academy_content" parent="menu_academy" name="Academy Content"/>

模型之间的关系

我们已经了解了直接保存在记录中的一对“基本”的字段。基本字段有很多个。第二种字段类别是关系型字段,用于关联字段到另外一个字段(模型内部或者跨模型)。

为了演示,我们来创建一个courses 模型。每个课程包含一个teacher字段,关联到一个教员的记录,但每个教员可以教授很多课程:

academy/models.py

name = fields.Char() biography = fields.Html()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_unlinkaccess_academy_teachers,access_academy_teachers,model_academy_teachers,,1,0,0,0access_academy_courses,access_academy_courses,model_academy_courses,,1,0,0,0让我们也添加视图以便查看和编辑课程的教员:

academy/views.xml

</field> </record> <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"> <tree string="Courses"> <field name="name"/> <field name="teacher_id"/> </tree> </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> <label for="name"/> <field name="name"/> <label for="teacher_id"/> <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

name = fields.Char() biography = fields.Html() course_ids = fields.One2many('academy.courses', 'teacher_id', string="Courses")class Courses(models.Model): _name = 'academy.courses'academy/views.xml

<form> <sheet> <label for="name"/> <field name="name"/> <label for="biography"/> <field name="biography"/> <field name="course_ids"> <tree string="Courses" editable="bottom"> <field name="name"/> </tree> </field> </sheet> </form> </field>

讨论和通知

Odoo提供了一些技术模型,它不会直接实现业务需求,但它们向业务对象添加了功能而无需手工构建。

这其中包括了聊天系统,它是Odoo邮件和消息系统的一部分,它可以向任何模型添加通知和讨论主题。该模型简单的继承(_inheritmail.thread 模型,并添加message_ids 字段到它的表单视图来显示讨论主题。讨论主题按每条记录显示。

对于我们的学院(academy)来说,它可以允许讨论课程来处理例如计划修改或者教员和助教之间的讨论:

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

<label for="teacher_id"/> <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系统中的产品设置了一个电商网站。我们可以方便的通过指定类别的产品使得课程订阅可销售。

除了之前常规的继承,它意味着可以通过product模型替换我们的course模型,并就地扩展产品(添加任何东西到产品中)。

首先我们需要为website_sale添加依赖,这样我们可以同时获得产品(通过销售sale)和电商界面:

academy/__manifest__.py

'version': '0.1', # any module necessary for this one to work correctly 'depends': ['website_sale'], # always loaded 'data': [重启Odoo,更新您的模块,现在网站中有了一个商城板块,列出了预设(通过演示数据)的产品。

第二步是通过product.template替换 courses 模型,并为courses添加一个新的类别:

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

<field name="name">Lester Vaughn</field> </record> <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></odoo>academy/models.py

name = fields.Char() biography = fields.Html() course_ids = fields.One2many('product.template', 'teacher_id', string="Courses")class Courses(models.Model): _inherit = 'product.template' 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_unlinkaccess_academy_teachers,access_academy_teachers,model_academy_teachers,,1,0,0,0academy/views.xml

</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"/>基于这个安装,一些课程现在在商城中可用了,即使它们还需要进行搜索。

更改现有的视图

目前,我们已经简要的看了:

我们还要了解一下现有记录和视图的修改。我们将在商城页面中修改它们。

视图更改可以通过创建扩展视图来完成,它应用在原始视图上,并可以对原始视图做修改。这些修改的视图可以添加或者删除,不需要修改原有的视图,使得新元素的试用和恢更加方便。

因为我们的课程是免费的,不需要在商城页面中显示它们的价格,因此我们计划修改视图并隐藏价格为零的字段。第一个任务是找出显示价格的视图,这可以通过自定义>HTML编辑器,它可以让我们读取到页面呈现相关的各种模板。查看这些模板,“产品项目”看起来是对应的视图。

更改视图框架可以通过3个步骤完成:

  1. 创建一个新视图
  2. 通过设置新视图的inherit_id为要修改的视图的外部ID,来扩展要修改的视图
  3. 在框架中,使用标签xpath 从修改的视图选择和修改元素
academy/templates.xml

<div class="oe_structure"/> </t> </template> <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> <!-- <template id="object"> --> <!-- <h1><t t-esc="object.display_name"/></h1> --> <!-- <dl> -->我们将更改第二件事情是使得产品分类的边栏按默认可见:自定义>产品分类,让您可以切换产品分类树的显示和隐藏(用于过滤主显示)。

这可以通过扩展模板的customize_showactive 字段来实现:扩展的模板(例如我们刚创建的)可以设置customize_show=True。这个选项将在自定义菜单中显示包含选择框的视图。使得管理员可以激活或者禁用它们(以及方便的自定义它们的网站页面)。

我们只需要简单的修改产品分类记录并设置它默认为active="True":

academy/templates.xml

</xpath> </template> <record id="website_sale.products_categories" model="ir.ui.view"> <field name="active" eval="True"/> </record> <!-- <template id="object"> --> <!-- <h1><t t-esc="object.display_name"/></h1> --> <!-- <dl> -->这样,产品分类边栏会在Academy模块安装时自动启用。

关键词:教程,官方,发文

74
73
25
news

版权所有© 亿企邦 1997-2025 保留一切法律许可权利。

为了最佳展示效果,本站不支持IE9及以下版本的浏览器,建议您使用谷歌Chrome浏览器。 点击下载Chrome浏览器
关闭