1.车辆类型
从原始档案我们可以看到车辆类型子模块,有以下几个字段,然后我们开始一步一步添加车辆类型子模块。字段名 | 类型 | 说明 |
类型编号 | 字符型 | 新增字段 |
车辆类型 | 字符型 | |
首保公里数 | 整型 | |
日常保养公里数(每次) | 整型 | |
备注 | 文本型 | 新增字段,个人习惯 |
类型编号:ODOO中在设计表的时候,每个表都有name这个字段,ODOO会使用name字段作为记录的标题。在其他模型中调用的时候也会被引用。一个子模块,一般情况下我们需要创建数据模型、设置访问权限、创建视图层三步。如果有特殊需求还要添加业务逻辑层。新增数据模型
在左侧列表myaddons->peijia->models上点击鼠标右键,选择new->Python File。在弹出的对话框输入文件名car_type,点击Python file,PyCharm在指定的目录自动生成文件并打开。# -*- coding: utf-8 -*-# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&# NebulaERP odoo14.0# QQ:50282# 邮件:50282@qq.com# 手机:1111111111# 作者:'Nebula'# 公司网址: www.erpSoft.org# Copyright 2012-2020 Nebula# 日期:2020/3/25# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&from odoo import fields, modelsclass NebulaCarType(models.Model): _name = "nebula.car.type" _description = "车辆类型" _order = 'name' name = fields.Char(string='类型编号', size=2, required=True, copy=False, index=True) name_type = fields.Char(string='类型名称') active = fields.Boolean(default=True, string='是否启用', size=2) first_maintain = fields.Integer(string='首保公里数', size=8, default=3500) every_maintain = fields.Integer(string='日常保养公里数', size=8, default=7500) note = fields.Text('备注') # 数据库层面的约束,所以效率比较高 _sql_constraints = [('check_uniq_name', 'unique(name)', '不允许同类型编号'), ('check_uniq_type', 'unique(name_type)', '不允许同类型编号') ]
# -*- coding: utf-8 -*-在第一行声明编码是utf-8。
用“#&&&&&&&&&&&&&”包裹部分是版权相关信息,读者可自行处理。from odoo import fields, models:Python代码导入语句,从Odoo包中导入 fields, models模块。我们如果对fields等有兴趣的话,可以按住ctrl键,再用鼠标点击fields,PyCharm就会打开对应的模块文件,使用者可以阅读源码,这就是开源的魅力。接下来空两行的原因是因为PyCharm默认会用PEP8编码规范检查使用者编写的代码,如果只空一行的话,提示需要2个空行,发现1行。为了代码美观大方,可读性强,我们尽量遵从PEP8编码规范来编写代码。class NebulaCarType(models.Model):定义一个类,为了不和其他开发者或者官方类重名,建议采用项目名做前缀,也有开发者缩写做前缀的,或者公司有命名规范的,可依实际情况使用命名方法。这里类名采取驼峰命名法,该类继承自models.Model,或者说这个类是models.Model派生出来的一个子类。_name = "nebula.car.type":_name属性定义了ODOO全局对该模型引用的标识符。ODOO引用模型的时候用的是_name属性,而不是类名。这里命名方式是用“.”来分隔,一般来说,用该模型业务相关的单数形式+ . + 英文单词来命名,比如系统中的pay.payment就是支付业务的支付模型的意思。笔者因car同名可能性太高,故在前面追加nebula英文名,同样也是个人喜好或看公司规定了。_description = "车辆类型":_description属性不是必须的,但是为模型提供了一个用户友好的名称,后面可以看到,在设计视图的时候,ODOO会自动提取该字段显示。_order = 'name':设置浏览模型记录时或列表视图的默认排序。这个值是SQL语句中order by 使用的字符串,所以可以传入符合SQL语法的任意值。name = fields.Char(string='类型编号', size=2, required=True, copy=False, index=True)注:结构化查询语言(Structured Query Language)简称SQL,结构化查询语言是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统;sql 语句就是对数据库进行操作的一种语言。active字段用于激活记录,默认active= True的记录才显示。有时候我们想隐藏某些记录的话,需要将active设置为False。_sql_constraints = [('check_uniq_name', 'unique(name)', '不允许同类型编号')]类似这个语法是一种约束方式,_sql_constraints是odoo的属性,是一个元组的列表,每个元组是一个数据库约束。元组的第一个元素是约束名字,第二个元素是约束规则(数据库postqresql 约束规则),第三个参数是如果违反约束弹出来的警告信息。在models目录下的__init__.py文件中引入car_type文件。设置访问权限
权限通过security/ir.model.access.csv文件来实现,如果没有请自行添加该文件。
内容如下:
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlinkaccess_nebula_car_type,nebula.car.type,model_nebula_car_type,group_peijia_manager,1,1,1,1
id:access_nebula_car_type是记录的外部标识符,模块唯一name:nebula.car.type描述性标题,默认规则是模块名.类名model_id:模型的外部标识符,ODOO自动生成的,一般是model_模块名称,点用_代替,group_id:指明授权的安全组,这里给group_peijia_manager组授权。perm_write,perm_create,perm_unlink:模块读、写、创建、删除权限。这里就是给peijia管理组全部权限,赋值1即有权限。在之前添加权限组的时候已经把管理员添加到peijia管理组里面,所以我们用管理员登录是可以使用该模块的。
我们需要检查这个文件是否在__manifest__.py中data段被引用,没有则添加。
我们在'security/groups.xml',下添加一行记录并保存:'security/ir.model.access.csv',
请注意顺序,ir.model.access.csv调用了groups.xml定义的权限组名,基于先声明再使用的原则,所以顺序不能错。
创建视图层
视图层为用户界面的描述,用XML文件定义,ODOO自动生成界面和交互操作功能。我们一般将视图层存放在views/目录下。创建表单视图
在views目录新建car_type_views.xml文件,内容如下:<?xml version="1.0" encoding="utf-8"?><odoo> <!-- 车辆类型列表 --> <act_windowid="peijia.action_car_type_views"name="车辆类型" res_model="nebula.car.type" view_mode="tree,form" /></odoo>
这里可以看到act_windows id的值和添加菜单项action的值相同。这里odoo会自动按照默认视图模版显示。在__manifest__.py文件中,data段的views/car_views.xml前面添加‘views/car_type_views.xml',引入视图文件。添加菜单项
我们在car_views.xml中继续为车辆类型添加菜单,在原顶级菜单下,添加二级菜单:<menuitem id="menu_peijia_base_data" name="基础资料" sequence="70" parent="menu_peijia_root"/>
<menuitem id="menu_car_type_views" name="车辆类型" parent="menu_peijia_base_data" sequence="110" action="peijia.action_car_type_views"/>
id:是记录的外部标识符,菜单唯一值,方便其他菜单引用。sequence:菜单顺序,ODOO会先按菜单级次再按sequence值从小到大排序action:会调用该子模块表单视图中ID为指定值的视图。查看效果
升级完成后,点击左上角图标,点击汽车陪驾,进入汽车陪驾模块。因目前只有汽车类型模块,且之前已经设置管理员有该模块的权限,所以ODOO会直接进入该模块。我们点击创建按钮,在默认的录入界面输入第一个车辆类型。点击保存后,显示单条记录,我们可以点击编辑按钮编辑该条记录,或点击创建按钮创建新的车辆类型,也可以点击动作菜单展开更多操作。存档:设置字段active为是,反之为取消存档,设置字段active为否,我们之前已经设置active在汽车类型中作为“是否启用”标识,所以存档操作影响是否启用字段值。关于复制:复制的时候,会以当前记录为蓝本,后台新建一条记录,再检查这条记录是不是符合条件,符合条件,就保存到数据库中,否则会提示错误信息。该子模块name字段设置为不可复制,且必填,所以提示name在复制的时候不能完成。解决方法可以设置一个默认值,每次复制后记得修改该默认值。当我们新建的时候,如果类型编号或类型名称和数据库中记录重复的时候,也会提示错误。class NebulaCarType(models.Model): _name = "nebula.car.type" _description = "车辆类型" _order = 'name' name = fields.Char(string='类型编号', size=2, required=True, copy=False, index=True, default='99') name_type = fields.Char(string='类型名称', required=True, copy=False, default='待修改') active = fields.Boolean(default=True, string='是否启用', size=2) first_maintain = fields.Integer(string='首保公里数', size=8, default=3500) every_maintain = fields.Integer(string='日常保养公里数', size=8, default=7500) note = fields.Text('备注') # 数据库层面的约束,所以效率比较高 _sql_constraints = [('check_uniq_name', 'unique(name)', '不允许同类型编号'), ('check_uniq_type', 'unique(name_type)', '不允许同类型名称') ]
子模块创建小结
在models目录下新增car_type.py文件,里面有数据模型定义 在models目录下的__init__.py文件中,添加对car_type文件的引用 检查项目目录下的__init__.py文件有对models目录的引用 修改security目录ir.model.access.csv文件,将该数据模型赋权限给陪驾管理组 检查项目目录下的__manifest__.py文件中data段有对ir.model.access.csv文件的引用 在views目录下新增car_type_views.xml文件,定义一个最基础的界面 在项目目录下的__manifest__.py文件中data段添加对car_type_views.xml的引用 在views目录下car_views.xml文件中新增对车辆类型的相关菜单信息完善界面
系统默认的界面可直接拿来使用,但是对于苛刻的用户来说,总是有各种需求,让我们继续完善界面。在xml文件中定义视图的记录,如下代码,代码来源于odoo官方文档。<record model="ir.ui.view" id="view_id">
<field name="name">view.name</field>
<field name="model">object_name</field>
<field name="priority" eval="16"/>
<field name="arch" type="xml">
<!-- view content: <form>, <tree>, <graph>, ... -->
</field>
</record>
这条记录会转换成ir.ui.view表中的数据,供odoo调用。<!-- view content: <form>, <tree>, <graph>, ... -->这里可以插入form、tree、graph等视图。如果遇到更新错误或不生效等问题, 可以在ir_ui_view数据表里删除对应视图记录后再更新。<treestring="Idea list"><fieldname="name"/><fieldname="inventor_id"/></tree>有几列就写几列的字段名称。表单视图示例:<formstring="Idea form"><groupcolspan="4"><groupcolspan="2"col="2"><separatorstring="General stuff"colspan="2"/><fieldname="name"/><fieldname="inventor_id"/> </group><groupcolspan="2"col="2"><separatorstring="Dates"colspan="2"/><fieldname="active"/><fieldname="invent_date"readonly="1"/></group><notebookcolspan="4"><pagestring="Description"><fieldname="description"nolabel="1"/></page></notebook><fieldname="state"/></group></form>
<search><fieldname="name"/><fieldname="inventor_id"/></search>
下面将在car_type_views.xml中段中添加相关代码。添加表单视图代码
<recordmodel="ir.ui.view"id="peijia.form_car_type_views"> <fieldname="name">peijia.car.type.form</field> <fieldname="model">nebula.car.type</field> <fieldname="arch"type="xml"> <formstring="表单"> <sheet> <divclass="oe_button_box"name="button_box"/> <groupname="group_top"> <groupname="group_left"> <fieldname="name"/> <fieldname="active"/> </group> <groupname="group_right"> <fieldname="name_type"/> <fieldname="first_maintain"/> <fieldname="every_maintain"/> </group> <fieldname="note"widget="many2many_tags"/> </group> </sheet> </form> </field></record>
添加列表视图代码
<recordmodel="ir.ui.view"id="peijia.tree_car_type_views"> <fieldname="name">peijia.car.type.tree</field> <fieldname="model">nebula.car.type</field> <fieldname="priority">1</field> <fieldname="arch"type="xml"> <treestring="列表"> <fieldname="active"/> <fieldname="name"/> <fieldname="name_type"/> </tree> </field></record>
添加搜索视图代码
<recordmodel="ir.ui.view"id="peijia.search_car_type_views"> <fieldname="name">peijia.car.type.search</field> <fieldname="model">nebula.car.type</field> <fieldname="arch"type="xml"> <search> <fieldname="name"/> <fieldname="name_type"/> </search> </field></record>
将原代码act_window部分全部删除,用推荐代码替换。<recordmodel="ir.actions.act_window"id="peijia.action_car_type_views"> <fieldname="name">车辆类型</field> <fieldname="res_model">nebula.car.type</field> <fieldname="view_mode">tree,form</field></record>
最后,我们在应用中升级陪驾模块,就可以看到效果了。关键点
代码中<odoo><data></data></odoo>格式是odoo约定的格式,请勿更改。<record></record>表示是一条记录。model的值一般情况下是odoo中的一个特殊的表。field:不同的name代表不同的意思,请根据实际情况理解,实在不行先搁置。Odoo中定义了字段的显示形式,不同字段类型的字段都有其不同的默认widget负责展示。我们也可以在视图文件上,为具体字段指定具体的widget,以达到我们想要的展示效果。widget="statusbar":头部状态条标签widget="selection" :下拉选择标签widget="mail_followers" :关注者标签widget="mail_thread" :消息标签widget="progressbar" :进度条,按百分比标签widget="one2many_list" :一对多列表标签widget="many2many_tags": 多对多显示标签widget="many2many_kanban": 看板标签widget="char_domain" :字符域标签widget="monetary" :价格(和精度位数相关)标签、金额标签widget="float_time" :单精度时间标签widget="sparkline_bar": 燃尽标签创建默认数据
留个预习作业,请参考下篇中创建默认数据方法,创建汽车类型的默认数据。