Odoo开发之记录集 – 使用模型数据
Odoo 12开发之记录集 – 使用模型数据
一·启动服务链接数据库
# 1.启动服务,链接数据库 ./odoo-bin shell -c debian/odoo.conf -d library_db # 2. self 当前操作的对象 res.users(1,) # 3. self._name # 当前模块名称 ,获得记录集模型名 ‘res.users‘ # 4. self.login # 记录值,至于怎么用.未知 ‘__system__‘ # 5. self.name # name 值为OdooBot OdooBot
二·执行环境
环境属性
# 1. self.env , 获得当前环境 <odoo.api.Environment object at 0x7f78a26026a0> # 2. self.env中的执行环境属性 # env.cr 正在使用的数据库游标(cursor) <odoo.sql_db.Cursor object at 0x7f9df38efc50> # env.user 是当前用户的记录 res.users(1,) # env.uid 是会话用户的id 1 # env.context 是会话上下文的不可变字典 {‘lang‘: ‘en_US‘, ‘tz‘: ‘Europe/Brussels‘} # 由于是 frozendict 由odoo 自行封装的字典,不可变 env.context[‘test‘]=‘test‘ 错误: NotImplementedError: ‘__setitem__‘ not supported on frozendic # search([(‘name‘,‘like‘,‘Ad‘)]) 搜索查询,search和domain表达式结合使用 self.env[‘res.partner‘].search([(‘name‘,‘like‘,‘Ad‘)]) # browse() 也是搜索查询,browse放id列表如[1,2,3,4] self.env[‘res.partner‘].browse([1,2,3,4])
环境上下文
### 环境上下是带有会话数据的字典. ### 作用:用于客户端和服务端ORM和业务逻辑中. 可以将信息从一个视图中传递到另一个视图中. # 比如:上一个视图中活跃的id,通过点击链接或者按钮.将默认值带入到下一个视图中. # 形式: {‘lang‘: ‘en_US‘, ‘tz‘: ‘Europe/Brussels‘, ‘uid‘: 2}
# 1. 查看上下文命令 self.context_get() self.env.context # lang :用户语言 tz:时区信息 uid:当前用户的id
修改记录集执行环境
### 记录集执行环境是不可变的.不可被修改,因此需要创建一个新的环境来修改 # 1. env.with_context({diciionary}) # 替换原上下文为新的上下文 # 2. env.with_context(key=value,...) # 修改当前上下文,为一些键设置值 # 3. env.sudo(user) # 传入一条用户记录并返回该用户的环境.如果未传用户,则使用 __system__超级用户. 可绕过安全规则执行指定操作 # env.ref()函数 , 传入一个外部标识符字符串并返回它的记录 self.env.ref(‘base.user_root‘) res.users(1,)
三· 记录集和作用域domain查询数据
创建记录
### search方法 接收一个域表达式并返回符合条件的记录集. 空域[]将返回所有的记录 # 关键字参数: # order是一个数据库查询语句种的 order by使用的字符串.通常是一个逗号分隔的字段名列表。每个字段都可接DESC关键字,用于表示倒序排列。 # limit 设置获取记录的最大条数 # offset 忽略钱n条记录,配合limit使用 # 用法: self.env[‘res.partner‘].search([(‘name‘, ‘like‘, ‘Pac‘)]) # 结果 res.partner(42, 62) ### search_count()方法 返回记录条数. 先知道条数,节约内存 # 用法 self.env[‘res.partner‘].search_count([]) #结果 681 ### browse()方法接收一个ID列表或单个ID并返回这些记录的记录集 # 用法 self.env[‘res.partner‘].browse([42, 62]) # 结果 res.partner(42, 62)
域表达式
### domain用于过滤数据记录. 使用的是特殊语法来供Odoo ORM解析 # 写法: (‘字段名’, ‘运算符’, ‘值’) 组成的元组 # 字段名:是一个有待过滤的字段,可用点号标记,来表示关联模型种的字段 # 值: 分为两种运行上下文: ① 窗口操作或字段属性等客户端,使用原生字段值,不能使用点标记符 ② 服务端可以是一个对象 # 运算符 # 比较: <,>,<=,>=,=,!= # =like 和 =ilike # like匹配 ‘%value%‘模式,ilike与其相似. # not like 和 not ilike # child of 支持层级关联的模型中 查找层级关系种的子级值 # in 和 not in 在和不在 # 多条件,即包含多个元祖 默认是 AND 运算符 # 例子: 此例子为编造 self.env[‘res.partner‘].search([(‘message_follower_ids‘, ‘in‘, [user.partner_id.id]),(‘user_id‘, ‘=‘, user.id)]) # 显式逻辑运算符 ‘&‘符号表示 AND 运算符(默认值),管道运算符’|‘表示OR运算符 # 例子: [‘|‘,(‘message_follower_ids‘, ‘in‘, [user.partner_id.id]),‘|‘,(‘user_id‘, ‘=‘, user.id),(‘user_id‘, ‘=‘, False)]
四·记录集中访问数据
访问记录中数据
# 1.记录集仅有一条记录时,称为单例 self.name --> OdooBot ### 注意: 尝试访问有多条记录的记录集字段值会产生错误,所以在不确定操作的是否为单例数据集时就会产生问题。对于设计仅操作单例的方法, 可在开头处使用 self.ensure_one(),如果 self 不是单例时将抛出错误。
访问关联字段
### 包含:many-to-one, one-to-many和many-to-many # 对于many-to-one,其值可以是单例或空记录集 self.company_id ---> res.company(1,) self.company_id.name ---> ‘YourCompany‘ self.company_id.currency_id ---> res.currency(1,) self.company_id.currency_id.name ---> ‘EUR‘ # 空记录可像单例一样操作,访问其字段值不会返回错误而是返回 False self.company_id.parent_id ---> res.company() self.company_id.parent_id.name ---> False
访问时间和日期值
# 1.查询上次admin用户登录日期 self.browse(2).login_date ---> datetime.datetime(2019, 1, 8, 9, 2, 54, 45546) # 2. 可以利用python的datetime模块进行时间计算
Odoo 还在odoo.tools.date_utils模块中提供额外的便利函数
# start_of(value, granularity)是某个特定刻度时间区间的开始时间,这些刻度有year, quarter, month, week, day或hour # end_of(value, granularity)是某个特定刻度时间区间的结束时间 # add(value, **kwargs)为指定值加上一个时间间隔。**kwargs参数由一个relativedelta对象来定义时间间隔。这些参数可以是years, months, weeks, days, hours, minutes等等 # subtract(value, **kwargs)为指定值减去一个时间间隔 from odoo.tools import date_utils from datetime import datetime # 范围时间当前时间和指定时间参数:week,本周周一那天.如今天是2020年5月27,一周前是2020年5月25 # 输入: date_utils.start_of(datetime.now(), ‘week‘) datetime.datetime(2020, 5, 25, 0, 0) # end_of 同理 末尾时间 # 输入:date_utils.end_of(datetime.now(), ‘week‘) datetime.datetime(2020, 5, 31, 23, 59, 59, 999999) # add 指定添加多长时间 # 输入: date_utils.add(datetime.today(), months=2) datetime.datetime(2020, 7, 27, 2, 40, 55, 424214) # subtract 指定减去多长时间 # 输入: date_utils.subtract(datetime.today(), months=2) datetime.datetime(2020, 3, 27, 2, 42, 21, 390561)
odoo.fields.Date和the odoo.fields.Datetime
# 1. fields.Date.today() # 返回当前日期,类型是datetime datetime.date(2020, 5, 27) # 2. fields.Datetime.now() # 返回当前日期+时间,类型是datetime datetime.datetime(2020, 5, 27, 2, 46, 10) # 3. fields.Date.context_today(record, timestamp=None) fields.Date.context_today(self, timestamp=None) datetime.date(2020, 5, 27) # 在会话上下文中返回带有当前日期的字符串。时间从记录上下文中获取。可选项timestamp参数是一个datetime对象,如果传入将不使用当前时间,而使用传入值 # 4. fields.Datetime.context_timestamp(record, timestamp) # 将原生的datetime值(无时区)转换为具体时区的datetime。时区从记录上下文中提取,因此使了前述函数名。
转换文本形式的日期和时间
# fields.Date和fields.Datetime都提供了如下函数 # 1. to_date将字符串转换为date对象 # 2. to_datetime(value)将字符串转换为datetime对象 # 3. to_string(value)将 date和datetime对象转换成字符串格式 # 4. Odoo 预设文本格式默认值: odoo.tools.DEFAULT_SERVER_DATE_FORMAT ---> %Y-%m-%d odoo.tools.DEFAULT_SERVER_DATETIME_FORMAT ---> Y-%m-%d %H:%M:%S from odoo import fields # 输入: fields.Datetime.to_datetime(‘2019-01-12 13:48:50‘) datetime.datetime(2019, 1, 12, 13, 48, 50) # 注意: 其他格式时间字符串转换成日期类型需要使用 datetime.strptime单独转换 from datetime import datetime # 输入: datetime.strptime(‘1/1/2019‘, ‘%d/%m/%Y‘) datetime.datetime(2019, 1, 1, 0, 0)
五·记录中写入
# odoo写入分为两种模式: # 1. 使用对象形式直接分配 . 简单但一次只能操作一条记录,效率较低 # 2. 使用write() 方法 . 写入关联字段时使用特殊语法,但每条命令可写入多个字段和记录,记录计算更为高效
对象形式分配值写入
# 查询一条数据 root = self.env[‘res.users‘].browse(1) # 更改root对象name值 root.name = ‘Superuser‘ # root.name Superuser ###
通过 write()方法写入
# 用write()方法来同时更新多条记录中的多个字段,仅需一条数据库命令 # write() 接收一个字典来进行字段和值的映射 # 得到一个空对象 Partner = self.env[‘res.partner‘] # 查询值 recs = Partner.search( [(‘name‘, ‘ilike‘, ‘Azure‘)] ) # 修改值, 修改成功为True recs.write({‘comment‘: ‘Hello!‘}) ### 在写入many-to-one字段时,写入的值必须是关联记录的ID。 例如,我们不用self.write({‘user_id’: self.env.user}),而应使用self.write({‘user_id’: self.env.user.id}) ### 写入to-many字段时,写入的值必须使用和 XML 数据文件相同的特殊语法 比如,我们设置图书作者列表为author1和author2,这是两条 Partner 记录。| 管道运算符可拼接记录来创建一个记录集,因此使用对象形式的分配可以这么写 publisher.child_ids = author1 | author2 # 使用write()方法 book.write( { ‘child_ids‘: [(6, 0, [author1.id, author2.id])] } ) ### (4, id, _)添加一条记录 ### (6, _, [ids])替换关联记录列表为所传入的列表
写入日期和时间值
### 可以使用文本形式值写入日期和时间: # 如: # 搜索到一个对象 demo = self.search([(‘login‘, ‘=‘, ‘demo‘)]) # 更改demo.login_date值 demo.login_date = ‘2019-01-01 09:00:00‘ # 查看 demo.login_date ---> datetime.datetime(2019, 1, 1, 9, 0)
创建和删除记录
#创建和删除记录 通过 create()和unlink()模型方法实现 ### create方法 # 得到一个空的对象 ,这个对象仅被加载到了内存种,没有实际保存到数据库种 Partner = self.env[‘res.partner‘] # 创建一个对象,此时就被保存到数据库种 new = Partner.create({‘name‘: ‘ACME‘, ‘is_company‘: True}) res.partner(64,) # 查看cutomer属性值 print(new.customer) # customer标记默认为 True ### unlink()方法会删除记录 # 搜索到某条记录 rec = Partner.search([(‘name‘, ‘=‘, ‘ACME‘)]) rec.unlink() # 删除 partner 关联字段的串联删除
拷贝模型记录值
### copy() 方法,会自动创建一条记录.这条记录会被保存到数据库中 # 查询出一条记录 demo = self.env.ref(‘base.user_demo‘) # 拷贝 new = demo.copy({‘name‘: ‘Daniel‘, ‘login‘: ‘daniel‘, ‘email‘: ‘‘})
六·重构记录集
# 1. recordset.ids 返回记录集元素的ID列表 # 2. recordset.ensure_one()检查是否为单条记录(单例);若不是,则抛出ValueError异常 # 3. recordset.filtered(func)返回一个过滤了的记录集,func可以是一个函数或一个点号分隔的表达式来表示字段路径,可参见下面的示例。 # 4. recordset.mapped(func)返回一个映射值列表。除函数外,还可使用文本字符串作为映射的字段名。 # 5. recordset.sorted(func)返回一个排好序的记录值。除函数外,文本字符串可用作排序的字段名。reverse=True是其可选参数。
>>> rs0 = self.env[‘res.partner‘].search([]) >>> len(rs0) 48 >>> starts_A = lambda r: r.name.startswith(‘A‘) >>> rs1 = rs0.filtered(starts_A) >>> print(rs1) res.partner(63, 59, 14, 35) >>> rs1.sorted(key=lambda r: r.id, reverse=True) res.partner(63, 59, 35, 14) >>> rs2 = rs1.filtered(‘is_company‘) >>> print(rs2) res.partner(14,) >>> rs2.mapped(‘name‘) [‘Azure Interior‘] >>> rs2.mapped(lambda r: (r.id, r.name)) [(14, ‘Azure Interior‘)]
rs1 | rs2是一个集合的并运算,会生成一个包含两个记录集所有元素的记录集 rs1 + rs2是集合加法运算,会将两个记录集拼接为一个记录集,这可能会带来集合中有重复记录 rs1 & rs2是集合的交集运算,会生成一个仅在两个记录集中同时出现元素组成的数据集 rs1 – rs2是集合的差集运算,会生成在rs1中有但rs2中没有的元素组成的数据集 # 还可以使用分片标记,例如: rs[0]和rs[-1]分别返回第一个和最后一个元素 rs[1:]返回除第一元素外的记录集拷贝。其结果和rs – rs[0]相同,但保留了排序 # 删除或添加元素来修改记录集 self.author_ids |= author1:如果不存在author1,它会将author1加入记录集 self.author_ids -= author1:如果author1存在于记录集中,会进行删除 self.author_ids = self.author_ids[:-1]删除最后一条记录
七·底层 SQL 和数据库事务
# 数据库引入运算在一个数据库事务上下文中执行 # 通过数据库游标self.env.cr # 执行事务缓冲的写运算 ,提交数据 self.env.cr.commit() # 取消上次 commit之后的写运算,如果尚未 commit,则回滚所有操作 self.env.cr.rollback() # execute() 方法 执行SQL语法 self.env.cr.execute() 参数一: 运行的SQL 语句, 可选参数:一个用作 SQL 参数值的元组或列表。这些值会用在%s占位符之处。 # 用法: self.env.cr.execute("SELECT id, login FROM res_users WHERE login=%s OR id=%s", (‘demo‘,1) self.env.cr.execute("SELECT id, login FROM res_users WHERE login=%s OR id=%s", (‘demo‘,1)) ### select 查询记录 # fetchall() 函数以元组列表的形式获取所有行 # 输入:self.env.cr.fetchall() [(1, ‘__system__‘), (6, ‘demo‘)] # dictfetchall()则以字典列表的形式获取 # 输入: self.env.cr.dictfetchall() [{‘id‘: 1, ‘login‘: ‘__system__‘}, {‘id‘: 6, ‘login‘: ‘demo‘}] ### 修改DML操纵语言 self.env.cache.invalidate()
相关推荐
yangkang 2020-11-09
lbyd0 2020-11-17
sushuanglei 2020-11-12
85477104 2020-11-17
KANSYOUKYOU 2020-11-16
wushengyong 2020-10-28
lizhengjava 2020-11-13
星月情缘 2020-11-13
huangxiaoyun00 2020-11-13
luyong0 2020-11-08
腾讯soso团队 2020-11-06
Apsaravod 2020-11-05
PeterChangyb 2020-11-05
gaobudong 2020-11-04
wwwjun 2020-11-02
gyunwh 2020-11-02
EchoYY 2020-10-31
dingyahui 2020-10-30