一.前言
只有一个猫猫明细表(my_cats)是远远不够的,还记得之前提到过的关系字段吗?也就是One2many和Many2one,不记得也没关系,请移步(小白读odoo参考手册–字段)
当然,使用关系型字段,必须先创建一个新的模型,那么我们就创建一个猫舍模型,用来当猫猫的家,一个猫舍会对应多只猫猫,多只猫猫对应一个猫舍,这就是关系字段,一对多,多对一的关系.
还记得创建一个模块是怎么操作的吗?不记得请移步(odoo新手创建模块(一)–简单搭建),只要记得先简单的搭建模型,当程序启动后,无异常,再去添加更多的功能即可.小白在这里就一步到位了,毕竟不能把东西再像第一章那样拆碎了给大家看,有点水文章,大家看看如何实现就可以了,自己搭建的时候一定要循序渐进,在简单的搭建后,没有报错后在逐步添加完善功能.毕竟不这样做很容易出错.
二.新增模型
我们在models文件夹下,创建My_Cats_Home.py文件,并添加更多的字段:
# -*- coding: utf-8 -*-
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
class MycatsHome(models.Model):
_name = "my.cats.home"#模型的名称,升级后后台会在pg库里创建相对于的数据表
_description = "猫舍"#模型的描述,界面的显示模型的名称
name = fields.Char(string="猫舍名称") #Char--文本类型,string表示前端展现时的字段描述
capacity = fields.Integer("猫舍容量")
capacity_rate = fields.Float(string="猫舍安放比", compute="_compute_rate")
capacity_group=fields.Float("猫舍安放数", compute="_compute_rate",store=True)
#compute:计算字段,参数是定义的方法
#store=True,表示此数据会被录入数据库,当字段有compute属性的时候,一般不会将此部分数据录入数据库,唯有store=True才可以解决
cat_tots = fields.One2many('my.cats', 'cats_home', string="猫猫")
#关系型字段One2many,
#第一个参数是一对多,多的数据库的名称,
#第二个参数是多对一的字段名称,这个名称是在My_Cats_HomePage.py所定义的
#第三给为前端显示的名称系字段,
@api.depends('capacity', 'cat_tots')
#计算字段需要修饰器@api.depends
#参数为字段,即当该字段值发生改变时,调用此方法
#与上面字段添加的compute参数一致
def _compute_rate(self):
#一个计算猫舍安放比的方法
for record in self:
if not record.capacity:
record.capacity_rate = 0.0#为该模型显示的数据
record.capacity_group = 0.0#为记录入数据库的数据,后续关联的时候使用
#如果猫舍容量为空时,默认为0
else:
#否则,100*猫猫数量/猫舍容量
record.capacity_rate = 100.0 * len(record.cat_tots) / record.capacity#返回一个计算的结果
record.capacity_group = len(record.cat_tots)#将数据记录数据库,后面会有调用
@api.constrains('capacity','cat_tots')
#constrains修饰器,用于评估和检查,当参数字段的值变化时便开始检查,如果检查不通过,则字段值不会发生变化,在前端页面也会抛出一个异常
def check_age(self):
#作用与下面onchange部分是重合的,但我们都知道onchange只提供提示,当用户忽略提示执意要使用非法值时,就束手无策了
#所有在onchange上,补充数据库校验,确保不会有非法值录入系统
if self.capacity <= 0:
raise UserError("猫舍容量不能小于0!!!")
if self.capacity < len(self.cat_tots):
raise UserError("猫猫数量超过了猫窝容量值!!!")
@api.onchange("capacity", "cat_tots")
#onchange修饰器,想必大家都很熟悉了吧?当里面的参数的值发生改变时,调用此方法
#逻辑:当"猫舍容量"<=0时,报错,告诉猫舍容量异常
def _onchange_capacity(self):
if self.capacity <= 0:
return {
'warning': {
'title': "猫舍容量值不正确",
'message': "猫舍容量不能小于0",
'type': 'notification'
}
}
#逻辑:当"猫舍容量"小于存放猫猫的个数,则提示猫猫数量异常
if self.capacity < len(self.cat_tots):
return {
'warning': {
'title': "猫猫太多了",
'message': "猫猫数量超过了猫窝容量值",
},
}
同目录下,找到My_Cats_HomePage.py文件,并添加关系字段:
cats_home = fields.Many2one('my.cats.home', string="猫舍")
#与My_Cats_Home.py表做关联,这里所定义的cats_home ,正是cat_tots关系型字段的第二个参数
capacity = fields.Integer(string='猫舍容量', related='cats_home.capacity')
#我们将My_Cats_Home.py的字段带过来,related的参数就是关联字段所对应的具体字段
capacity_group=fields.Float(string="猫舍安放数", related='cats_home.capacity_group')
@api.constrains('cats_home')
#两个关联模块的双保险
def check_age(self):
if self.capacity < self.capacity_group:
raise UserError("猫猫数量超过了猫窝容量值!!!")
仿照砖厂管理员的(ODOO13 开发教程四 模型中的字段)Many2one与One2many是成对出现的,虽然在不同的模型中,但彼此关联.
这里不要忘了在models文件夹下,init.py里引用我们定义的模块:
# -*- coding: utf-8 -*-
from . import My_Cats_HomePage
from . import My_Cats_Home
三.编写视图
在views文件夹下,创建并打开My_Cats_Home_view.xml文件:
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record id="my_catshome_view_form" model="ir.ui.view">
<field name="name">猫舍管理</field>
<field name="model">my.cats.home</field>
<field name="arch" type="xml">
<form>
<header>
</header>
<sheet>
<group col="4">
<field name="name"/>
<field name="capacity"/>
</group>
<group>
<field name="capacity_rate" widget="progressbar"/>
</group>
<notebook>
<page string="猫窝猫猫">
<field name="cat_tots" readonly="1"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="my_catshome_view_tree" model="ir.ui.view">
<field name="name">猫舍管理</field>
<field name="model">my.cats.home</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="capacity"/>
<field name="capacity_rate" widget="progressbar"/>
<field name="cat_tots"/>
</tree>
</field>
</record>
<record id="my_catshome_action" model="ir.actions.act_window">
<field name="name">猫舍管理</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">my.cats.home</field>
<field name="view_mode">tree,form</field>
<field name="domain">[]</field>
<field name="context">{}</field>
</record>
</data>
</odoo>
在同目录下,打开My_Cats_HomePage_view.xml文件,在末尾增加菜单项:
<menuitem name="猫猫管理系统2.0" id="my_cats_menu_root" sequence="50" groups="base.group_user"
web_icon="mrp,static/description/icon.png"/>
<menuitem action="my_cats_action"
id="menu_my_cats"
name="猫猫管理系统"
parent="my_cats_menu_root"
sequence="21"
/>
<!--上面是之前添加的菜单,下面是这章新加的菜单,这里是为了方便告诉大家此行代码插在了什么地方-->
<menuitem action="my_catshome_action"
id="menu_my_catshome"
name="猫舍管理"
parent="my_cats_menu_root"
sequence="22"
/>
<!--这里的动作(action)是在My_Cats_Home_view.xml中定义的,
父级菜单(parent)与之前的菜单挂在同一级下
sequence:菜单的顺序,这里选则22,则在猫猫管理系统菜单的后面
-->
并在my_cats_view_form添加关联字段:
<group>
<field name="cats_home"/>
<field name="description"/>
</group>
创建完视图后,在根目录下manifest.py中的data列表中添加xml文件:
'data': [
'data/ir_sequence_data.xml',
'security/ir.model.access.csv',
'views/My_Cats_HomePage_view.xml',#上面都是之前加过的模块,下面是本章新增的视图
'views/My_Cats_Home_view.xml',
],
四.配置安全/权限文件夹security
找到security文件夹下,的ir.model.access.csv:添加代码:
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_my_cats_Operator,my_cats_Operator,model_my_cats,base.group_user,1,1,1,1
access_my_cats_home_Operator,my_cats_home_Operator,model_my_cats_home,base.group_user,1,1,1,1
其中,第三行的内容是这章新增的,第一行与第二行是我们之前的内容
然后我们安装启动,就完成了.
这里小白创建了一个猫舍,将两只猫猫都放了进去:
五.效果
在猫猫关联系统的from视图中,可以看到猫猫所对应的猫舍
而点开这个猫舍,就会呈现该猫舍的详情:
点击猫舍管理:
当我们修改猫舍容量时,提示的报错:
猫猫数量大于猫舍的报错:
当我们不管onchange的提示,依然要修改值的报错: