self 多会出现在这样几种情况下
class AModel(models.Model):
_name = 'a.model'
def a_method(self):
# self can be anything between 0 records and all records in the database
self.do_operation()
def b_method(self):
for rec in self:
rec.do_operation()
在AModel中的 a_method 方法中,self作为第一个参数传入。
在odoo源码中,注释这样说:# self可以是数据库中介于0条记录和所有记录之间的任意值。
也就是说,self 是当前类的实例或实例集合,在b_mothod中也可以看出,self是可以遍历的集合。
我在源码中还看到了这么一句:
Methods defined on a model are executed on a recordset, and their ``self`` is a recordset::
意思是:模型上定义的方法,在记录集上执行,这时它们的"self"是记录集。
通过b_method方法中,对self的遍历,也可以确定的是,每一条实例都封装了当前模型的信息。
在odoo源码中,我们也许遇见过下面的这种代码书写方式:
def _compute_product_count(self):
product_data = self.env['lunch.product'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id'])
data = {product['category_id'][0]: product['category_id_count'] for product in product_data}
for category in self:
category.product_count = data.get(category.id, 0)
在这段代码中,对self进行了遍历,每条记录即为category,使用category为模型中的product_count字段直接赋值,这也说明了self中封装了模型的记录集。
你可能还看见过这行代码:
self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", [self.currency_eur_id, company.id])
这里self调用了cr游标,执行了SQL语句,说明self中封装了cr 信息。
equipment.owner_user_id = self.env.user.id
self调用了self.env.user.id信息,说明self封装了当前环境。
当然,self 还封装了许多信息,比如上下文,感兴趣可以用断点看一下self 的结构。
接下来说说self封装的常用的env,env 记录了用户当前所在位置的环境,比如:
self.env.context.get('not_unlink_on_discard')
可以获取到当前环境的上下文(是字典结构)。
除此之外,我们可以将当前环境切换到其他环境上,就像这样:
emp_res = self.env["hr.employee"].search([])
这样就可以 获取到 员工 的记录集合。
根据id 获取XML的ID :
self.env.ref('base.res_partner_1')
self 常用的ORM API
# 按条件查找出符合的记录集
self.env["hr.employee"].search(["name","=","ZERONE"])
# 以id搜索过滤,接收参数为id的列表
res = self.env["hr.employee"].browse([1,2,3])
# 在hr_employee 中创建一条新的记录
self.env["hr.employee"].create({
"name":"Zerone",
...
})
# 更新记录数据
self.env["hr.employee"].search([("id","=",1)]).write({"field_1":"xxx"})
# 将已有记录复制,生成一条新的记录,在这里只有属性copy=True的字段的值才会被复制,其他的字段值会以默认值或空填充
res_copy = self.self.env["hr.employee"].search(["name","=","ZERONE"]).copy()
# 获取字段的默认值,包括上下文、用户默认值和模型本身的默认值。fields是字段列表,可自己定义
@api.model
def default_get(self, fields):
print(fields)
rec = super(payment_register, self).default_get(fields)
...
return rec
# 取符合条件的记录的条数count
notes_count = self.env['note.note'].search_count([('user_id', '=', self.env.uid)])
# 根据传入的参数,搜索显示名称与给定名称模式匹配的记录 name_search接收四个参数,但只有第一个是必须的,返回的是符合条件的记录集
ns_res = self.env['res.partner'].name_search('Vlad', args=[('user_ids.email', 'ilike', 'vlad')])
ns_res = self.env['res.partner'].name_search('Vlad', operator='ilike')
partners = res_partner.name_search('Vlad', limit=1)
# 根据传入的字段名列表,返回对应的值
self.env['survey.user_input'].browse(answer_own.ids).read(['state'])
# 根据分组字段,返回记录分组列表
debit_groups = analytic_line_obj.read_group(
domain=domain + [('amount', '<', 0.0)],
fields=['account_id', 'currency_id', 'amount'],
groupby=['account_id', 'currency_id'],
lazy=False,offset=0, limit=None, orderby=False
)
对于read_group 方法,domain,fields,groupby三个参数是必须的,
domain 是匹配符合条件的记录集,
fields 是 取出的字段
groupby 是按那些字段什么排序,按在数组中的顺序
lazy 为true的话,分组只会根据groupby列表中的第一个元素分组,为false时,根据列表中所有字段排序
orderby 按哪个字段排序,offset limit 是从第offset条,往后取limit条。