(05)odoo数据库和业务操作
以一个例子开头
* To-do 向导
# 配置文件
__openerp_.py:
{ 'name': 'To-do Tasks Management Assistant',
'description': 'Mass edit your To-Do backlog.',
'author': 'Daniel Reis',
'depends': ['todo_user'],
'data': ['todo_wizard_view.xml'], }
__init__.py:
from . import todo_wizard_model
# 模型 todo_wizard_model.py
# -*- coding: utf-8 -*-
from openerp import models, fields, api
from openerp import exceptions # will be used in the code
import logging
_logger = logging.getLogger(__name__)
class TodoWizard(models.TransientModel):
_name = 'todo.wizard'
task_ids = fields.Many2many('todo.task', string='Tasks')
new_deadline = fields.Date('Deadline to Set')
new_user_id = fields.Many2one( 'res.users', string='Responsible to Set')
@api.multi
def do_mass_update(self):
self.ensure_one()
if not (self.new_deadline or self.new_user_id):
raise exceptions.ValidationError('No data to update!')
# else:
_logger.debug('Mass update on Todo Tasks %s', self.task_ids.ids)
if self.new_deadline:
self.task_ids.write({'date_deadline': self.new_deadline})
if self.new_user_id:
self.task_ids.write({'user_id': self.new_user_id.id})
return True
@说明几点:
@ 引入了日志功能,记录的级别如下4级
_logger.debug('A DEBUG message')
_logger.info('An INFO message')
_logger.warning('A WARNING message')
_logger.error('An ERROR message')
# 表单 todo_wizard_view.xml
<openerp>
<data>
<record id="To-do Task Wizard" model="ir.ui.view">
<field name="name">To-do Task Wizard</field>
<field name="model">todo.wizard</field>
<field name="arch" type="xml">
<form>
<div class="oe_right">
<button type="object" name="do_count_tasks"
string="Count"/>
<button type="object" name="do_populate_tasks"
string="Get All"/>
</div>
<field name="task_ids"/>
<group>
<group>
<field name="new_user_id"/>
</group>
<group>
<field name="new_deadline"/>
</group>
</group>
<footer>
<button type="object" name="do_mass_update"
string="Mass Update" class="oe_highlight"
attrs="{'invisible':[('new_deadline','=',False),('new_user_id', '=',False)]}"/>
<button special="cancel" string="Cancel"/>
</footer>
</form>
</field>
</record>
<!-- More button Action -->
<act_window id="todo_app.action_todo_wizard"
name="To-Do Tasks Wizard"
src_model="todo.task" res_model="todo.wizard"
view_mode="form" target="new" multi="True"/>
</data>
</openerp>
@说明:有一个批量更新的逻辑 do_mass_update
# 业务逻辑 todo_wizard_model.py
@api.multi
def do_mass_update(self):
self.ensure_one()
if not (self.new_deadline or self.new_user_id):
raise exceptions.ValidationError('No data to update!')
# else:
_logger.debug('Mass update on Todo Tasks %s', self.task_ids.ids)
if self.new_deadline:
self.task_ids.write({'date_deadline': self.new_deadline})
if self.new_user_id:
self.task_ids.write({'user_id': self.new_user_id.id})
return True
@说明:@api.one 这个是返回一个记录用的 这是主要用 task_ids,所以这里不用
@api.multi 这是是返回一记录列表用
self.ensure_one() 确保是单个,否则报异常
这里有异常处理 :
from openerp import exceptions
raise exceptions.Warning('Warning message')
raise exceptions.ValidationError('Not valid message')
# 自动加载代码变化,这是主要python代码变化,就要手动重启服务,有点麻烦
从而有了 ./odoo.py -d v8dev --auto_reload 自动加载
这个选项可以放到配置文件中 auto_reload = True
有先安装一个依赖,才可以用 pip install pyinotify
# 向导窗口的动作
可以重新打开表单,从而一个表单上的多个按钮可以同时用
@api.multi
def do_reopen_form(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'res_model': self._name, # this model
'res_id': self.id, # the current wizard record
'view_type': 'form',
'view_mode': 'form',
'target': 'new'}
全选:
@api.multi
def do_populate_tasks(self):
self.ensure_one()
Task = self.env['todo.task']
all_tasks = Task.search([])
self.task_ids = all_tasks
# reopen wizard form on same
* 服务端的操作
# 开启命令行交互操作
https://www.odoo.com/apps/modules/8.0/shell/.
把那个shell模块,放到addons中去
$ ./odoo.py shell -d v8dev
指定账套,采用命令交互模式启动
这样就可以测试代码中用到的一些对象,如:
>>> self 得到当前用户对象,这里是超级用户对象
res.users(1,)
>>> self.name
u'Administrator'
>>> self._name
'res.users'
>>> self.env
<openerp.api.Environment object at 0xb3f4f52c>
# 用关系字段
>>> self.company_id
res.company(1,)
>>> self.company_id.name
u'YourCompany'
>>> self.company_id.currency_id
res.currency(1,)
>>> self.company_id.currency_id.name
u'EUR'
#模型中的查询
用self只能得到方法中的字段,但 self.env 可以得到任意其它模型
self.env['res.partner'] 得到合作伙伴对象
运用search() 或 browse() 得到对象的记录
search() 里面是domain表达式,若为空[]则搜索所有的记录
模型中有active字段,默认为True搜索,还有一些参数如下:
order 排序 limit 返回最大记录数 offset 记录数启点位置
search_count()得到记录总数
browse()主要根据记录id 返回记录 多个,采用列表形式。单个时可以直接传入
例子:
>>> self.env['res.partner'].search([('name','like','a')])
res.partner(36, 5, 30, 31, 20, 27, 10, 24, 29, 22, 18)
>>> self.env['res.partner'].browse([5,30])
res.partner(5, 30)
>>> self.env['res.partner'].browse(5)
res.partner(5,)
>>> self.env['res.partner'].browse([5])
res.partner(5,)
#记录上的操作
>>> admin = self.env['res.users'].browse(1)
>>> admin.name='Superuser'
>>> admin.name
@创建一个新记录,但还没有持久化到数据库
>>> Partner = self.env['res.partner']
>>> new = Partner.create({'name':'ACME','is_compnay':True})
>>> print new
res.partner(37,)
@删除记录
>>> rec = Partner.search([('name','=','ACME')])
>>> rec.unlink()
True
@把partner对象全部comment的值改为 'Hello!'
res.partner(37,)
>>> Partner.write({'comment':'Hello!'})
@复制一个记录
>>> demo = self.env.ref('base.user_demo') 得到demo这个用户对角
>>> new = demo.copy({'name': 'Daniel', 'login': 'dr', 'email':''})
>>> self.env.cr.commit()
注:命令效互时操作记录不会记录到数据库中,只有用了 self.env.cr.commit() 后才
会持久化到数据库中
#事务操作和原生sql
self.env.cr 数据库操作句柄
self.env.cr.commit() 事务提交
self.env.savepoit() 事务提交点,回滚时可以来指定回滚到什么位置
self.evn.rollbakc() 事务回滚
原生sql操作 self.env.cr.execute()
self.env.cr.execute("SELECT id, login FROM res_users WHERE login=%s OR id=%s",('demo',1))
self.env.cr.fetchall()
#时间和日期
%Y-%m-%d 和 %Y-%m-%d %H:%M:%S
>>> from openerp import fields
>>> fields.Datetime.now()
'2016-01-25 07:12:34'
>>> fields.Datetime.from_string('2016-12-08 22:23:22')
datetime.datetime(2016, 12, 8, 22, 23, 22)
fields.Date.today() 得到当前的日期是服务器端的
fields.Datetime.now()得到当前的时间是服务器端的
fields.Date.context_today(record,timestamp=None) 从上下文得到当前的日期
fields.Datetime.context_timestamp(record,timestamp) 从上下文得到当前的时间
from_string(value) 字符串转换为日期或时间对象
to_string(value) 日期或时间对象转换为字符串
#关系字段操作
当采用活动记录模式时,用 create() 或 write() 赋关联字段时,不要用对象,要用外键id
不要 self.write({'user_id':self.env.user})
而要改为 self.write({'user_id':self.evn.user.id})
#操作记录集 (集合操作)
rs1 | rs2 求并集 是指两个集合的所有元素构成的集合
rs1 + rs2 求两个集直接连起来,不管重复
rs1 & rs2 求交集 是指两个集合元素相同的部分构成的集合
rs1 - rs2 求差集 是指其中一个集合中除去另一个集合相同元素以后剩余的元素构成的集合
例子说明:
>>> Party=self.env['res.partner']
>>> Party.search([])
res.partner(36, 5, 7, 33, 32, 23, 30, 31, 19, 35, 20, 17, 21, 34, 27, 12, 8, 9, 15, 25, 14, 10, 24, 3, 1, 26, 29, 22, 6, 13, 11, 28, 16, 18)
>>> rs1=Party.browse([1,3,5,7])
>>> rs2=Party.browse([7,32,33])
>>> rs1 | rs2
res.partner(32, 1, 3, 5, 7, 33)
>>> rs1 + rs2
res.partner(1, 3, 5, 7, 7, 32, 33)
>>> rs1 & rs2
res.partner(7,)
>>> rs1 - rs2
res.partner(1, 3, 5)
记录切片(相当于序列切片操作)
>>> rs1
res.partner(1, 3, 5, 7)
>>> rs1[0]
res.partner(1,)
>>> rs1[-1]
res.partner(7,)
>>> rs1[1:]
res.partner(3, 5, 7)
记录集追求记录去除
self.task_ids |= task1 task1在task_ids中没有就增加 <=> self.write([(4, task1.id, False)])
self.task_ids -= task1 task1 在task_ids 减去 <=> self.write([(3, task1.id, False)])
self.task_ids = self.task_ids[:-1] task_ids 删除最后一个记录
<=> self.write([(3, self.task_ids[-1].id, False)])
其它记录集操作
record in recordset 检测一个记录是否在一个记录集中
record not in recordset 检测一个记录是否不在一个记录集中
recordset.ids 记录ID集
recordset.ensure_one() 检测是一个记录
recordset.exists() 若存在返回一个备份
recordset.filtered(func) 过滤记录集
recordset.mapped(func)
recordset.sorted(func) 排序后
len(rs1) 得到记录数
>>> rs1
res.partner(1, 3, 5, 7)
>>> len(rs1)
4
rs1 = rs0.filtered(lambda r:r.name.startswith('H')) 通过name过滤
rs2 = rs0.filtered('is_company') 通过is_compay 为True 来过滤
rs2 = rs0.mapped('name') 得到只有name字段 组成记录集 列表
rs1.sorted(key=lambda r:r.id,reverse=True) 根据id 反向排序
* 执行环境
self.env 具有的属性:
env.cr 数据库操作句柄
env.uid session中的user的id
env.user session中的user对象
env.context session中的上下文,以字典方式组成
环境对象是不能改的只能换,重建
env.sudo(user) 给了用户记录就返回该用户记录,没有,就返回超级用户
env.with_context(dictionary) 换了原有的session
env.with_context(key=value,...) 换指定键的值
env.ref() 要一个 External ID 做为参数
>>> self.env.ref('base.user_root') 这是超级用户的external ID
res.users(1,)
* 客户端效互的模型方法
#
read([fields]) 像search() 但返回来,每一行是一个字典类型
search_read([domain],[fields],offset,limit,order=None) 根据 read()后的结果搜索
load([fields],[data]) 用于ssv数据导入
export_data([fields],raw_data=False) 用于csv数据导出
name_get() 得到(ID,name) 元组的列表 默认是计算 display_name
name_search(name='', args=None, operator='ilike', limit=100) 得到(ID,name) 元组的列表 ,按条件
name_create(name) 创建一个新记录,只用name字段
default_get([fields]) 返回创建新记录时,指定字佰的默认值
fields_get() 得到模型定义的哪些字段
fields_view_get() 得到指定视图类型下可用的字段, 视图类型,有tree ,form,等
#覆盖默认方法
create() 和 write() 这两个方法常扩展
例子如下:
@api.model
def create(self, vals):
# Code before create
# Can use the `vals` dict
new_record = super(TodoTask, self).create(vals)
# Code after create
# Can use the `new` record created
return new_record
@api.multi
def write(self, vals):
# Code before write
# Can use `self`, with the old values
super(TodoTask, self).write(vals)
# Code after write
# Can use `self`, with the new (updated) values
return True
#模型方法修饰器
@api.one 一次得到一条记录
@api.multi 一次得到一个记录集
@api.model 这是类级别静态方法
@api.return(model) 显性返回一个模型
@api.depends(fld1,...)
@api.constrains(fld1,...)
@api.onchange(fld1,...) 可用于警告
#调试
import pdb; pdb.set_trace()
(05)odoo数据库和业务操作的更多相关文章
- MySQL数据库的常见操作(七)
MySQL数据库的常见操作 1.创建数据库 2.创建重名的数据库以及如何查看警告信息 3.设置数据库的编码方式(默认为utf8) 4.修改和查看数据库的编码方式 5.删除数据库 6.6.删除已经删除了 ...
- 怎样加快master数据库的写操作?分表原则!将表水平划分!或者添加写数据库的集群
1.怎样加快master数据库的写操作?分表原则!将表水平划分!减少表的锁定时间!!! 或者或者添加写数据库的集群!!!或者添加写数据库的集群!!! 2.既然分表了,就一定要注意分表的规则!要在代码层 ...
- Odoo(OpenERP)开发实践:通过XML-RPC接口访问Odoo数据库
Odoo(OpenERP)服务器支持通过XML-RPC接口访问.操作数据库,基于此可实现与其他系统的交互与集成. 本文是使用Java通过XMLRPC接口操作Odoo数据库的简单示例.本例引用的jar包 ...
- Odoo(OpenERP)开发实践:通过XML-RPC接口訪问Odoo数据库
Odoo(OpenERP)server支持通过XML-RPC接口訪问.操作数据库,基于此可实现与其它系统的交互与集成. 本文是使用Java通过XMLRPC接口操作Odoo数据库的简单演示样例.本例引用 ...
- SQL Server性能调优——报表数据库与业务数据库分离
前段时间把公司的主数据库切了,分成业务库和报表库,业务库向报表库进行实时的Replication.这个项目的上线提升了系统的性能和可维护性,现在把设计时的考量和所做的工作重新回顾一下,作为备忘. 项目 ...
- 【Docker】 .Net Core 3.1 webapi 集成EF Code First,使用MySql进行业务操作 、配置swagger (三)
系列目录: [Docker] CentOS7 安装 Docker 及其使用方法 ( 一 ) [Docker] 使用Docker 在阿里云 Centos7 部署 MySQL 和 Redis (二) [D ...
- python操作mysql数据库的相关操作实例
python操作mysql数据库的相关操作实例 # -*- coding: utf-8 -*- #python operate mysql database import MySQLdb #数据库名称 ...
- MySQL数据库定义与操作语言
文章为作者原创,未经许可,禁止转载. -Sun Yat-sen University 冯兴伟 实验1.1 数据库定义 (1)实验目的 理解和掌握数据库DDL语言,能够熟练地使用SQL DDL语句 ...
- 在php中需要用到的mysql数据库的简单操作
1.数据库连接 1.1用windows命令行链接数据库服务器 几个DOS命令 在DOS环境下命令后面没有分号,在MySQL环境下,命令后面有分号 进入盘符: 语法:盘符: 进入盘符下的某个文件夹 语法 ...
随机推荐
- 【leetcode❤python】 20. Valid Parentheses
#-*- coding: UTF-8 -*-#利用栈的思想#如果输入的左测扩则入栈,如果输入为右侧扩,判断其是否与当前栈顶配对,如果匹配则删除这一对,否则return False#'(', ')', ...
- ubuntu下ssh登陆阿里云服务器(ubuntu系统)中文乱码问题
研究了几天终于解决了... 原文地址: http://blog.csdn.net/a__yes/article/details/50489456 问题描述: 阿里云的服务器ubuntu系统,wind ...
- [HDOJ5763]Another Meaning(KMP, DP)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5763 题意:给定两个字符串a和b,其中a中的字符串如果含有子串b,那么那部分可以被替换成*.问有多少种 ...
- EF实体框架常见问题
1,无法为具有固定名称“System.Data.SqlClient”的 ADO.NET 提供程序加载在应用程序配置文件中注册的实体框架提供程序类型“System.Data.Entity.SqlServ ...
- 程序间数据共享与传递:EXPORT/IMPORT、SAP/ABAP Memory
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- Windows Internals学习笔记(二)系统架构
参考资料: 1. <Windows Internals> 2. http://bestcbooks.com 3. Windows Drive Kit 4. Microsoft Window ...
- Redis基础知识之————使用技巧(持续更新中.....)
一.key 设计技巧 把表名转换为key前缀 如, tag: 第2段放置用于区分区key的字段--对应mysql中的主键的列名,如userid 第3段放置主键值,如2,3,4...., a , b , ...
- iOS企业版打包(转载)
转自 http://www.cnblogs.com/shenlaiyaoshi/p/5472474.html 神来钥匙-陈诗友 iOS 企业版 打包 使用 iOS 企业版的证书发布应用可以跳过 A ...
- 学习日记day7:代码结构规范
1:绝对定位不是随便用的. 2:一定要用相对定位控制文档流,在相对定位里面使用绝对定位控制具体的位置. 3:代码结构尽量简化. 不要加不必要的span: 不要加不必要的类: 4:控制字体样式的类尽量写 ...
- 使用ioctl“实现”自定义的系统调用
http://www.educity.cn/Linux/1242138.html 最近做的项目跟Linux内核的关系比较大,我们的项目需要在用户态触发一些内核态的代码运行.众所周知,内核态的代码是不能 ...