Odoo ORM API(三)- Model Reference

本文详细介绍了OPENERP中模型的定义方式、结构属性及常用方法。涵盖了模型创建、读取、更新、删除等操作的具体实现,同时深入解析了字段查询、视图获取等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Model Reference

class openerp.models.Model(pool, cr)
OPENERP 的 Models 都是继承自这个 class

class user(Model):
    ...

这个在每个数据库中值会被系统实例化一次。

Structual attributes

  • _name
    business object name, 通常是 ‘.’,用于存放在 module的命名空间中

  • _rec_name
    可选的,用于将某个字段设置成name, 将被 osv 的 name_get()调用(默认为 name

  • _inherit

    • 如果 _name 设置了,那么它的值就是 他想继承的的父类的 _name,如果只是继承一个父类,可以直接设置成str,将会把数据存在自己的表上
    • 如果 _name 没有设置,将会直接在父类的表上进行拓展修改。
  • _order
    默认的order选项(default: ‘id’), 如果search()中设置了 order 参数,将以后者为准

  • _auto
    是否创建一个数据库表(default:True),如果设置为False,需要复写 init()用以创建数据表

  • _table
    当创建数据表时,使用的名字,通常会根据默认参数自动生成

  • _inherits
    传入一个字典,key 是继承的model的_name,值为field的名字。

_inherits = {
    'a.model': 'a_field_id',
    'b.model': 'b_field_id'
}

这个新的model,与父类相关的值都不会存在自己的表中,而是存储在父类的表中。

  • _constrains
    list of (constraint_function, message, field) ,8.0之后不再赞成使用,建议使用 api.constrains()

  • _sql_constraints
    list of (name, sql_definition, message) triples , 当建立数据表时,用以限制。

  • _parent_store
    Alongside parent_left and parent_right,设置一个 nested set 用以快速查询当前model的record。(default: False)

CRUD (create,retrieve,update,delete)

  • create(vals) -> record
    为这个 model 创建一个新的 record。
    这个新的 record 使用提供的值来初始化,如果必要的话,从default_get() 取值
Name描述
参数vals(dict),{‘field_name’: field_value, …}
返回值一个创建的新的record
报错AcessError: 如果当前user没有创建这个object的权限,或者用户试图绕过访问规则创建请求对象.
ValidateError: 给selection字段传入一个无效的值。
UserError: 如果创建了一个循环调用,如:给一个res.partner设置它自己为自己的parent_id
  • browse([ids]) -> records
    根据提供的ids,返回对应id的record组成的recordset
    可以不提供Id,或者只有一个Id,或者sequence of ids

  • unlink()
    删除当前的recordsets
    可能会抛出 AcessError(和write一样) 或者 UserError(如果这个record是其它records的默认属性)

  • write(vals)
    把当前recordset中所有record根据提供的参数,修改值
    其余基本和 create 一样

    • 如果是数字类的 fields(Integer,Float),传入的value也应该是对应的 type
    • Boolean field 的话,就应该传入 boolean
    • Selection field,传入对应的选项,多数是str,极少为 integer
    • Many2one,应该传入对应record的 database id
    • 其它的非关系型的字段,就传入 str

      注意:
      由于历史的兼容性的原因, Date 和 Datetime fields 读写中得到的都是 str 类型,而非对应的 date 和 datetime 类型。date string 都是 UTC-only 的,format 格式为 "%Y-%m-%d""%Y-%m-%d %H:%M:%S"

    • One2many 和 Many2many 使用一个特殊的命令,还将这些record与这个字段关联起来
      这个命令就是 由多个元祖(3个元素)组成的列表,每一个元祖都是一条命令,它们将按顺序执行,通常是这些:

      1. (0, _, values) 给这个field 添加一个新的 record,这个新的record 是根据 values(dict)的值创建出来的。
      2. (1, id, values) 用values(dict)来更新这个 field 已经关联到的 id 为 传入 id的 record, 不能用在 create()
      3. (2, id, _) 将 id 为传入 id的record 从 field的关联中删除,并且将其从数据库中删除。不能用在create()中
      4. (3, id, _) 将 id 为传入 id的record 从 field的关联中删除,但是不从数据库中删除。不能作用在One2many字段上,也不能用在create()中
      5. (4, id, _) 将一个已经存在的id为传入id的record添加到field的关联中,不能作用在One2many字段上,
      6. (5, _, _) 将这个field的关联集清空,等同于对这个集合中的每一个record执行 (3, id, _) 命令。不能用在One2many,不用再create()
      7. (6, _, ids) 用ids这些records来替代原有field对应的关联集,等同于先对这个record执行(5, _, _),再对ids中的每一个record,执行(4, id, _)

      提示:
      上面 的 _ 都代表不重要的意思,通常填入 False 或者 0

  • read([fields])
    读取对应field的值,并将他们以字典的形式返回。每一个record一个字典,最后返回一个列表。

  • read_group(*args, **kwargs)
    Get the list of records in list view grouped by the given groupby fields

Name描述
参数cr - database cursor
uid - 当前用户id
domain - 普通的domain,表明在哪些符合要求的record进行read_group
fields(list) - 列出需要展现的字段
groupby(list) - 列出根据哪些字段来分组,这中间要么直接写出字段名称,或者field:groupby_function,groupby_function目前只支持day,week,month,quarter,year,并且只能作用于 Date 和 Datetime 类型的字段
offset(int) - 可选的,用以跳过几条record
limit(int) - 可选,只返回一定数目的record
context(dict) - 基本的context参数,比如lang、time zone
orderby(list),就和search()中的orderby一样,目前仅支持many2one
lazy(bool) - 如果为True,那么就只groupby第一个groupby,其它的groupby传入到__context key中。如果是False,一次性将所有的groupby全部执行
返回值多个dict(每个record一个dict)组成的list,每个dict包含:
the values of fields grouped by the fields in groupby argument
__domain: list of tuples specifying the search criteria
__context: dictionary with argument like groupby
返回类型[{‘field_name_1’: value, …]
异常AcessError: 如果当前user没有创建这个object的权限,或者用户试图绕过访问规则创建请求对象.

Searching

  • search(args[, offset=0][, limit=None][, order=None][, count=False])
    最主要的就是args中的domain
Name描述
参数args - 一个 search domain, 如果没有domain,传入一个空列表,表示所有
offset (int) 忽略多少个
limit(int) - 最大返回多少个
order(str),一个由field name组成的str,其中用逗号分隔
count(bool) - 如果设置为True,仅仅用来计数符合要求的数目,并且返回这个数。默认是False
返回值多数情况下,返回一个符合要求的recordset
报错AcessError: 如果当前user没有创建这个object的权限,或者用户试图绕过访问规则创建请求对象.
  • search_count(args) -> int
    返回符合domain的record的数目

  • name_search(name='', args=None, operator='ilike', limit=100) -> records
    name符合pattern的record筛选出来,包含 domian(args)
    相当于进行search()后,再name_get()

Name描述
参数name - 搜索的pattern
args - 一个 search domain, 如果没有domain,传入一个空列表,表示所有
operator(str),ilike, =,等
limit(int) - 最大返回多少个
返回类型list
返回值符合要求的record的 list of pairs (Id,text_repr)

Recordset operations

  • ids 返回这个recordset所有record的数据表id组成的list

  • ensure_one() 验证这个recordset的长度是否为1,否则抛出异常

  • exists() -> records ,返回这个recordset中所有实际存在的recordset。

  • filtered(func)
    返回这个func(rec)为True的所有record组成的recordset。这个func可以是一个函数,也可以是一个以点分隔的field names。

  • sorted(key=None, reverse=False)
    返回根据key排序的recordset,key和普通python sorted 的 key 差不多

  • mapped(func)
    将func作用于每一个record上,如果func返回recordset,那么总体就返回recordset,否则总体返回list
    func可以是 函数,也可以是以点分隔的field names。

Enviroment swapping

  • sudo([user=SUPERUSER])
    返回一个适用于传入user的recordset
    默认情况下,返回一个superuser权限的recordset,这将会直接越过 access control 和 record rule。

    注意:
    由于使用 sudo 将会越过各种权限设置,所以查询出来的数据可能会包含本来设置为区分的record
    比如(多公司环境下的record)

    而且,这个新的recordset 将不会被cache。所以,查询数据将会产生一定的延迟。

  • with_context([context][, **overrides]) -> records
    返回一个新的符合给定context的recordset

# current context is {'key1': True}
r2 = records.with_context({}, key2=True)
# -> r2._context is {'key2': True}
r2 = records.with_context(key2=True)
# -> r2._context is {'key1': True, 'key2': True}


  • with_env(env)
    返回一个新的符合给定env的recordset

注意:
这个新的environment将不会采用当期environment的cache,所以后续的数据查询将会有延迟,因为要直接从数据库中读取。

Fields and views querying

  • fields_get([fields][, attributes])
    返回每个field的definition
    返回值是一个dict,传入的field作为key。同样可以传入_inherit的model的field,每一个field对应一个字典,其中string,help和selection都会被自动翻译。
    Parameters
    allfields – list of fields to document, all if empty or not provided
    attributes – list of description attributes to return for each field, all if empty or not provided

  • fields_view_get([view_id | view_type='form'])
    Get the detailed composition of the requested view like fields, model, view architecture
    Parameters
    view_id – id of the view or None
    view_type – type of the view to return if view_id is None (‘form’, ‘tree’, …)
    toolbar – true to include contextual actions
    submenu – deprecated
    Returns dictionary describing the composition of the requested view (including inherited views and extensions)
    Raises
    AttributeError –
    if the inherited view has unknown position to work with other than ‘before’, ‘after’, ‘inside’, ‘replace’
    if some tag other than ‘position’ is found in parent view
    Invalid ArchitectureError – if there is view type other than form, tree, calendar, search etc defined on the structure

???

  • default_get(fields_list) -> default_values
    返回这个fields_list中所有field对应default value,这些default value由context,user default,和 models自己定义的决定。
    Parameters fields_list – a list of field names
    Returns 返回一个字典,fields_name : default value。如果这个field,有defualt value

  • copy(default=None)
    复制当前record,并用default更新
    Parameters default (dict) – dictionary of field values to override in the original values of the copied record, e.g: {‘field_name’: overridden_value, …}
    Returns new record

  • name_get() -> [(id, name), …]
    返回这个recordset中所有record对应的名字,默认是返回record的 display_name 字段。

    namedescrition
    Returnslist of pairs (id, text_repr) for each records
    Return typelist(tuple)
  • name_create(name) -> record
    通过 create() 创建一个新的record,但是只传入一个参数(display_name)。
    这个新的record将采用一切合适的default Value,包括context中包含的。

    namedescrition
    Parametersname – display name of the record to create
    Returnsthe name_get() pair value of the created record
    Return typerecord

Automatic fields

  • id

  • _log_access 默认为True

  • create_date 创建record的时间 type: datetime

  • create_uid 创建record的用户 type: res.users

  • write_date 最近一次修改的时间 type:datetime

  • write_uid 最近一次对其修改的用户 type: res.users

Reserved field names

有些字段名字,是作为保留字段,被预先定义好了。如果你要在某个model中实现这种相关的功能,可以通过定义这些名字的field来实现。

  • name type Char
    _rec_name 字段的默认值,通常用来显示一个record的可读的名字

  • active type Boolean
    用以全局的改变这个record的可见,如果active 被设置为False,那么绝大多数的search和listing中都不会显示

  • sequence type Integer
    修改order的标准,同时允许在tree view界面,进行拖曳,用以调整顺序

  • state type Selection
    一个object的周期,可以被用在field的states属性中

  • parent_id type Many2one
    设置各种层级,并且可以在domain中使用child_of operator

  • parent_left
    _parent_store 一起使用,通常是为了高效率的 tree structure

  • parent_right
    同上
<think>好的,用户让我详细讲解OdooORM API,我需要先回想一下自己对这个主题的理解。首先,OdooORM API是框架中非常重要的一部分,负责处理数据库操作,让开发者不用直接写SQL就能进行CRUD操作。用户可能已经有一定的Odoo基础,但想深入了解如何高效使用ORM,或者可能在开发中遇到了性能问题,想优化代码。 接下来,我应该分几个部分来讲解。首先,ORM种类型:Traditional、New和Bidirectional。需要解释每种的特点和使用场景。比如Traditional API使用方法装饰器,而New API在v8之后引入,用装饰器来兼容新旧版本,可能用户需要了解如何迁移旧代码或者在新项目中选择合适的API。 然后是常用的ORM方法,比如create、write、unlink,这些基本操作必须涵盖。搜索和查询部分,search和search_count、browse和exists的区别,可能需要举例说明。特别是domain的构造,用户可能需要知道如何组合条件。 记录集的操作部分,用户可能会关心如何处理多个记录,比如通过mapped、filtered、sorted等方法。这部分应该详细说明每个方法的参数和返回值,以及使用场景。比如mapped可以提取字段或调用函数,可能会影响性能,需要提醒用户注意。 上下文和环境的作用,比如with_context和env,用户可能在传递参数或切换环境时遇到问题,需要说明如何正确使用这些功能。 高级查询部分,比如read_group和name_search,这些在复杂报表或搜索功能中常用,可能需要举例说明参数的意义和用法。特别是read_group的分组统计,用户可能需要生成汇总数据,这时候这个方法就很有用。 最后,ORM的最佳实践,比如避免循环中的查询、使用缓存、批量操作,这些都是性能优化的关键点。用户可能在实际开发中因为不了解这些而遇到性能瓶颈,需要强调这些注意事项。 需要检查是否有遗漏的重要方法,比如name_get和name_create,虽然不常用,但在某些情况下还是必要的。另外,是否需要提到ORM的继承机制,比如扩展模型的方法?可能用户需要了解如何覆盖write或create方法,但题目可能更关注API的使用而不是扩展,所以暂时不深入。 还要注意语言表达清晰,结构分明,使用例子帮助理解。可能需要提醒用户注意版本差异,比如New API是从v8开始,而Odoo现在版本已经到v16,所以大部分情况下应该使用New API。同时,bidirectional API可能是指混合使用的情况,需要简单说明。 最后,总结部分要回顾重点,确保用户理解如何有效利用ORM API提升开发效率和性能。可能用户需要的是实际应用中的技巧,而不仅仅是理论,所以结合实例会更好。例如,在讲解mapped时,可以举例提取某个字段的列表,或者调用一个函数处理记录集。 还要考虑用户可能的误区,比如频繁调用search导致性能问题,或者没有正确使用缓存。在最佳实践中给出建议,帮助用户避免常见错误。 现在组织这些内容,确保逻辑连贯,覆盖主要知识点,同时保持语言简洁易懂。</think>OdooORM(对象关系映射)API 是其框架的核心组件之一,它允许开发者以面向对象的方式操作数据库,而无需直接编写 SQL。ORM API 抽象了底层数据库操作,提供了高效、安全且易用的数据管理接口。以下是 Odoo ORM API 的详细解析: --- ### 一、ORM API 的类型 Odoo ORM API 主要分为两种风格: 1. **Traditional API**(传统 API) 基于方法装饰器(如 `@api.multi`),主要在 Odoo 8 之前的版本中使用,现逐步被新 API 取代。 2. **New API**(新 API) 从 Odoo 8 开始引入,使用 `@api.model`、`@api.depends` 等装饰器,支持更简洁的代码风格和记录集(`self` 直接表示记录集)。 3. **Bidirectional API**(双向兼容) 新 API 支持混合使用,Odoo 内部会自动适配新旧方法。 --- ### 二、常用 ORM 方法 以下是核心 ORM 方法及其用途: #### 1. **基础操作** - **`create(vals)`** 创建新记录,返回新记录的记录集。 ```python record = self.env['model.name'].create({'field1': value1, 'field2': value2}) ``` - **`write(vals)`** 更新当前记录集。 ```python records.write({'field': new_value}) ``` - **`unlink()`** 删除当前记录集。 ```python records.unlink() ``` #### 2. **搜索与查询** - **`search(domain, limit=None, order=None)`** 根据 `domain` 条件搜索记录,返回匹配的记录集。 ```python domain = [('field', '=', value), ('state', 'in', ['done', 'cancel'])] records = self.env['model'].search(domain, limit=10, order='create_date DESC') ``` - **`search_count(domain)`** 返回匹配条件的记录数量(不加载实际数据,性能更高)。 ```python count = self.env['model'].search_count([('is_active', '=', True)]) ``` - **`browse(ids)`** 通过 ID 列表获取记录集(常用于从外部传入的 ID)。 ```python records = self.env['model'].browse([1, 2, 3]) ``` - **`exists()`** 验证记录是否仍在数据库中存在(避免操作已删除的记录)。 ```python valid_records = records.exists() ``` #### 3. **记录集操作** - **`mapped(func)`** 对记录集应用函数或提取字段值。 ```python names = records.mapped('name') # 提取所有记录的 name 字段列表 total = records.mapped(lambda r: r.qty * r.price) # 计算每个记录的值 ``` - **`filtered(func)`** 根据条件或函数过滤记录集。 ```python active_records = records.filtered(lambda r: r.is_active) ``` - **`sorted(key=None, reverse=False)`** 对记录集排序。 ```python sorted_records = records.sorted(key=lambda r: r.create_date, reverse=True) ``` #### 4. **上下文与环境** - **`with_context(**kwargs)`** 临时修改上下文(如传递默认值、语言或时区)。 ```python records.with_context(lang='fr_FR').name # 获取法语翻译的名称 ``` - **`env` 对象** 提供对当前环境(数据库、用户、上下文等)的访问。 ```python user = self.env.user # 当前用户 company = self.env.company # 当前公司 ``` --- ### 、高级查询与优化 #### 1. **`read_group(domain, fields, groupby, **kwargs)`** 执行分组统计(类似 SQL 的 `GROUP BY`),常用于生成报表。 ```python result = self.env['sale.order'].read_group( [('state', '=', 'done')], ['amount_total:sum'], # 汇总字段 ['partner_id'], # 分组字段 ) # 输出示例: [{'partner_id': (id, '名称'), 'amount_total': 1000}] ``` #### 2. **`name_search(name='', args=None, operator='ilike', limit=100)`** 根据名称模糊搜索记录(常用于前端关联字段的搜索)。 ```python self.env['res.partner'].name_search('John', limit=5) ``` #### 3. **`name_get()`** 返回记录的显示名称(格式:`[(id, "Display Name"), ...]`)。 ```python records.name_get() # 默认返回 (id, name) ``` --- ### 四、ORM 最佳实践 1. **避免循环中的查询** 在循环内执行 `search` 或 `write` 会导致性能问题,应批量操作。 ```python # 错误示例 for record in records: record.write({'field': value}) # 正确示例(批量操作) records.write({'field': value}) ``` 2. **利用缓存** ORM 会自动缓存字段值,多次访问同一字段不会触发额外查询。 3. **使用 `prefetch` 预加载数据** 在遍历记录集时,预加载关联字段以减少查询次数。 ```python records = records.with_prefetch() # 启用预加载 ``` 4. **优先使用 `search` 的 `limit` 和 `order`** 避免加载不必要的数据。 --- ### 五、总结 Odoo ORM API 通过抽象数据库操作,显著提升了开发效率。核心要点包括: - **记录集(Recordset)** 是操作的核心单位。 - **链式调用**(如 `records.filtered(...).mapped(...)`)可简化代码。 - **上下文** 和 **环境** 控制全局行为(如多公司、多语言)。 - **性能优化** 需关注批量操作和减少查询次数。 掌握这些方法后,可以高效地实现复杂业务逻辑,同时保持代码简洁和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值