https://www.odoo.com/documentation/11.0/howtos/website.html
学习内容:修改odoo端口,路由匹配和视图,t,数据库模型关联,继承,模块依赖
win 下开发
odoo管理员账号在数据库用户有一个数据库时会自动选择那个数据库-忘记管理员账号就没管理员账号,没有数据库时可以自己创建个新的odoo管理员账号
修改odoo端口 xmlrpc_port=1111(Google 一下就出来了 odoo change port)
1.python odoo-bin scaffold Academy myaddons
2.interpret browser requests and send data back.
解释浏览器请求和发送数据回来
路由
# -*- coding: utf-8 -*-
from odoo import http
class Academy(http.Controller):
@http.route('/academy/academy/', auth='public') # 监听访问的网站
# http://localhost:8069/academy/academy/
def index(self, **kw):
return "Hello, world" //返回给网站的内容
3.Templates QWeb 取数据渲染页面
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>
#raise ValueError('External ID not found in the system: %s' % xmlid)
#ValueError: External ID not found in the system: academy.index
#<template id="indexid">
<template id="index"> # 会生成academy.index 给render用
<title>Academy</title>
<t t-foreach="teachers" t-as="teacher"> # t-as 枚举名字
<p><t t-esc="teacher"/></p>
</t>
</template>
4.Storing data in Odoo
one:
academy/models.py
from odoo import models, fields, api
class Teachers(models.Model):
_name = 'academy.teachers'
name = fields.Char()
tow: 数据的访问权限
academy/__manifest__.py
# always loaded
'data': [
'security/ir.model.access.csv',
'templates.xml',
],
three: 配置表的权限
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
# this simply gives read access (perm_read) to all users (group_id:id left empty).
5.Accessing the data
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
<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>
6.引用其他模板的样式
Website support
default styling, theming via the website module.
academy/__manifest__.py
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['website'],
# always loaded
'data': [
# (not setup website=True)AttributeError: 'NoneType' object has no attribute 'name'
# Error to render compiling AST
academy/controllers.py
from odoo import http
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', {
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>
7.URLs and routing
展示url中的内容
academy/controllers.py
'teachers': Teachers.search([])
})
@http.route('/academy/<name>/', auth='public', website=True) # /academy/academy/代码访问上面的
# @http.route('/academy/academy/'
def teacher(self, name):
return '<h1>{}</h1>'.format(name)
validation
@http.route('/academy/<name>/', auth='public', website=True)
def teacher(self, name):
return '<h1>{}</h1>'.format(name)
@http.route('/academy/<int:id>/', auth='public', website=True) # 覆盖上面的/academy/<name>/匹配
def teacher(self, id):
return '<h1>{} ({})</h1>'.format(id, type(id).__name__)
8.records directly
academy/controllers.py # 配置model的路由
'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>
biography is shared between all teachers, because blocks are added to the template, and the biography template is shared between all teachers
7.t-field 存储视图的xml, 格式化时间
academy/models.py
_name = 'academy.teachers'
name = fields.Char()
biography = fields.Html()
<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"/>
t-field can also take formatting options
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>
human-readable version:
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>
or a relative display:
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>
8.Administration and ERP integration
To make it visible it must be available through an action, which itself needs to be reachable, generally through a menu.
academy/views.xml #menu 默认的form 和 tree
<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"/>
define a custom form
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"/>
Relations between models
courses model
academy/models.py
name = fields.Char()
biography = fields.Html()
class Courses(models.Model):
_name = 'academy.courses'
name = fields.Char()
# string xml 中展示的字段名, teacher_id 数据库中的列名,Many2one 返回个 id
teacher_id = fields.Many2one('academy.teachers', string="Teacher")
course’s view
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/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
the inverse relationship
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>
Field course_ids
does not exist 问题 model中对应字段不存在
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'
文档
9.模块继承
'depends': ['base', 'website', 'mail'],
继承
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/models.py
class Courses(models.Model):
_name = 'academy.courses'
_inherit = 'mail.thread'
name = fields.Char()
teacher_id = fields.Many2one('academy.teachers', string="Teacher")