odoo11 model+Recordset 基础未完待续
Model
一个模型代表了一个业务对象
本质上是一个类,包含了同django flask一样的数据字段 所有定义在模型中的方法都可以被模型本身的直接调用
现在编程范式有所改变,不应该直接访问模型,而是应该使用记录集 (RecordSet)
要实例化一个模型,你必须要继承openerp.model.Model 同Django Flask 实例代码:
from openerp import models, fields, api, _
class MyModel(models.Model):
_name = 'a.model' # 模型名称会被用作数据库表名
firstname = fields.Char(string="Firstname")
model继承
继承机制使用_inherit 示范代码:
class MyModelExtended(Model):
_inherit='a.model' #直接继承
_inherit=['a.model','a.other.model'] #直接继承
_inherit={'a.model':'field_name'} #多重继承
注意:可以单独修改某个字段的某个或多个属性
name = field.Char(string='New Value')
记录集 (Recordset)
所有模型在init中实例,同时这个实例也是对应记录集的实例.一个记录集表达了对应模型的经过排序的记录的集合
class AModel(Model):
#...
def a_func(self):
self.do_something() #这里self是一个记录集,介于类(class)与集合(set)之间的混合体
record_set = self
record_set.do_something()
def do_something(self):
for record in self:
print(record)
在运行这段代码时, self变量实际上是包含了很多记录的一个记录集的实例.
所以传入do_something的self是一个包含一系列记录的记录集.
如果使用@api.one装饰一个方法的话,它会遍历当前记录集的记录,此时的self就是当前这条记录.
注意:如果记录集只含有一条记录,你把这个装饰器用在该记录集上会导致中断!! (If you use it on a RecordSet it will break if recordset does not contains only one item.!!)
是否还是对record的值不理解,我也是先继续看吧.后面还有细讲的!!!!!!!!!!
支持的操作
类似集合的 联合,交,补等运算 ,属于 不属于
record in recset1 # 属于
record not in recset1 # 不属于
recset1 + recset2 # 扩展(extend)
recset1 | recset2 # 联合(union)
recset1 & recset2 # 交集(intersect)
recset1 - recset2 # 差补/相对补集(difference)
recset.copy() # 记录集的浅复制(被复制对象的所有变量都含有与原来的对象相同的值,而其所有的对其他对象的引用都仍然指向原来的对象)
只有 + 保留原集合的顺序
排序:
sorted(recordset, key=lambda x: x.column)example
对数据库的读和写
使用api的写 Active Record模式
设置属性(setting properties) 来写入数据库
record = self
record.name = 'new name'
此方法会更新缓存中的值并调用写方法来触发想数据库的写入动作
Active Record模式 注意事项 最主要是会导致高负载 范例:
@api.one
def dangerous_write(self):
self.x = 1
self.y = 2
self.z = 4
因为调用了api.one 对记录集里的每个记录的写操作都会被调用3次,name乳沟你的记录集有10条记录,一共会哟30次写操作
这早高负载任务里会导致性能问题.需要改写成如下:不调用api比较好
def better_write(self):
for rec in self:
rec.write({'x': 1, 'y': 2, 'z': 4})
# 或者
def better_write2(self):
# 给所有记录赋相同值
self.write({'x': 1, 'y': 2, 'z': 4})
空查询 (Browser_null) 链
空关系现在返回一个空的记录集
当查询的是字段是一个具有很多关联的,且值为空,这些关系都会被关联,最后返回一个空的记录集
环境 (Environment)
这里的环境 指的是对 记录指针(cursor)、用户id(user_id)、模型(model)、上下文(context)、记录集(Recordset)和缓存(cache)的封装。
于是乎,odoo11就不用传很多参数了
# 以前
def afun(self, cr, uid, ids, context=None):
pass
# 现在
def afun(self):
pass
访问环境的示范:
def afun(self):
self.env
# 或者
model.env
环境应该是不可变的,不能在方法里进行修改,因为它还存储着记录集的缓存等等信息。
修改环境
修改当前的上下文,需要使用with_context()方法:
self.env['res.partner'].with_context(tz=x).create(vals)
改变用户
环境提供了一个切换用户的辅助方法:
self.sudo(user.id)
self.sudo() # 缺省会使用 SUPERUSER_ID
# 或者
self.env['res.partner'].sudo().create(vals)
访问当前用户
self.env.user
使用XML id获取记录
self.env.ref('base.main_company')
清理环境缓存
由于我们的odoo中存在很多缓存,有用于模型,字段等类.
有时候可以使用记录指针 (cursor) 来直接插入/写数据,这种情况下需要将这些缓存无效:
self.env.invalidate_all()
一般动作(Common Actions)
搜索
变化如下 ps 官方宣称的域(domain)的变动没有在8.0版本里实现
search 方法直接返回一个记录集:
>>> self.search([('is_company', '=', True)])
res.partner(7, 6, 18, 12, 14, 17, 19, 8,...) #返回的记录集
>>> self.search([('is_company', '=', True)])[0].name
'Camptocamp'
使用env调用search:
>>> self.env['res.users'].search([('login', '=', 'admin')])
res.users(1,)
search_read
新功能search_read 功能:执行search并返回一个字典(dict)列表(list).
示范:获取所有合作伙伴的名称:
>>> self.search_read([], ['name'])
[{'id': 3, 'name': u'Administrator'},
{'id': 7, 'name': u'Agrolait'},
{'id': 43, 'name': u'Michel Fletcher'},
...]
search_count
search_count 方法返回符合搜索域(domain) 定义的记录数量:
>>> self.search_count([('is_company', '=', True)])
26L
检索
检索是从数据获取记录的标准方法.现在检索会返回一个记录集:
>>> self.browse([1, 2, 3])
res.partner(1, 2, 3)
写入
使用 Active Record 模式
@api.one
def any_write(self):
self.x = 1
self.name = 'a'
从记录写入
@api.one
...
self.write({'key': value })
# 或者
record.write({'key': value})
从记录集写入
@api.multi
...
self.write({'key': value })
# 它将写入到所有记录里
self.line_ids.write({'key': value })
多对多(Many2many) 一对多(One2many) 写入行为
未完待续`````````