创建一个基本模块
在 Odoo,我们通过创建模块来完成任务。
使用 Odoo 的搭建脚本工具可以创建一个基本模块。
$ ./odoo-bin scaffold Academy my-modules
安装演示模块
在创建了 academy 模块后,即使它什么也没做,我们也可以安装这个模块。启动 Odoo 服务,
$ ./odoo-bin --addons-path addons,my-modules
然后在应用中去掉过滤器,搜索 academy 就可以安装。
和浏览器交互
Controllers
处理浏览器的请求,返回结果。
from odoo import http
class Academy(http.Controller):
@http.route('/academy/academy/', auth='public')
def index(self, **kw):
return "Hello, world"
在浏览器中打开 http://localhost:8069/academy/academy/ , 你会看到如下的页面
image.pnghttp的路由路径可以随意定义,不一定要以模块名,这里是 academy 开始。我们建议以模块名开始避免冲突。
我们看到 @http.route , 这是 Python 的 decorator 的语法。http://www.cnblogs.com/Jerry-Chou/archive/2012/05/23/python-decorator-explain.html
使用模板
手动拼装 html 不是一件让人愉快的事情。
在 Odoo 中,我们使用 QWeb(https://www.odoo.com/documentation/11.0/reference/qweb.html#reference-qweb) 作为模板语言(你也可以使用其他基于 Python 的模板语言)。
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"],
})
这里将使用在 manifest.py 中注册的 academy.index 模板。
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-bin --addons-path addons,my-modules -d academy -u academy
在浏览器中打开会看到如下的页面
basic-list.png数据存储
首先定义好模型的类,
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',
],
# only loaded in demonstration mode
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
演示数据
可以用 XML 描述用于演示的静态数据
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>
这些数据会在演示模式下加载,在启动的时候会看到如下输出:
2018-06-26 12:07:29,908 20692 INFO phone580 odoo.modules.registry: module academy: creating or updating database tables
2018-06-26 12:07:29,997 20692 INFO phone580 odoo.modules.loading: loading academy/security/ir.model.access.csv
2018-06-26 12:07:30,030 20692 INFO phone580 odoo.modules.loading: loading academy/views/views.xml
2018-06-26 12:07:30,033 20692 INFO phone580 odoo.modules.loading: loading academy/views/templates.xml
2018-06-26 12:07:30,057 20692 INFO phone580 odoo.modules.loading: loading academy/demo/demo.xml
通过 PostgreSQL 客户端在 Tables
下可以观察到关联的数据
当我们修改静态数据之后,需要更新模块才能生效,使用 -u
参数在启动的时候更新模块,要同时使用 -d
参数才能生效。
访问数据
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"> -->
我们看到很关键的地方在 Teachers = http.request.env['academy.teachers']
这里将Teacher这个类引进了代码的上下文之中。
至此,我们看到了一个基本的渲染框架,以及一个简单的ORM框架,这些是构建一个网站的两个基本组成。
网站支持
odoo提供了一系列的模块帮助我们建立网站。目前为止,我们使用controllers
的方式很直接,odoo通过website
模块增加了更深度的整合以及包括样式、主体的服务。
-
增加
website
作为依赖; -
然后在 controller 设置
website=True
标志,这样我们可以通过the request object
获取更多变量,也可以在模板里使用website的layout; -
使用website的layout。
URLs和路由
用来做路由的字符串可以使用converter patterns
,不仅可以用来做路由匹配,还可以将数据作为本地变量使用。
academy/controllers.py
'teachers': Teachers.search([])
})
@http.route('/academy/<name>/', auth='public', website=True)
def teacher(self, name):
return '<h1>{}</h1>'.format(name)
image.png
converter patterns
不仅仅是数据提取,还可以用于转换和验证。
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__)
image.png
你可以使用model
来根据id获取记录。
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
})
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>
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>
这样就可以在列表中跳转到具体的记录
image.png image.png注意到slug
函数用于提取记录的id。
字段编辑
模型之间的关系
除了基本的字段之外,我们也可以用关系字段来表示模型之间的关系。
网友评论