当在odoo页面新建一条记录的时候,前端会通过rpc调用后端模型的default_get 函数,根据前端传入的字段列表,来获取相对应的字段默认值。
# odoo/models.py
@api.model
def default_get(self, fields_list):
""" default_get(fields_list) -> default_values
Return default values for the fields in ``fields_list``. Default
values are determined by the context, user defaults, and the model
itself.
:param list fields_list: names of field whose default is requested
:return: a dictionary mapping field names to their corresponding default values,
if they have a default value.
:rtype: dict
.. note::
Unrequested defaults won't be considered, there is no need to return a
value for fields whose names are not in `fields_list`.
"""
defaults = {}
parent_fields = defaultdict(list)
ir_defaults = self.env['ir.default'].get_model_defaults(self._name)
for name in fields_list:
# 1. look up context
key = 'default_' + name
if key in self._context:
defaults[name] = self._context[key]
continue
# 2. look up ir.default
if name in ir_defaults:
defaults[name] = ir_defaults[name]
continue
field = self._fields.get(name)
# 3. look up field.default
if field and field.default:
defaults[name] = field.default(self)
continue
# 4. delegate to parent model
if field and field.inherited:
field = field.related_field
parent_fields[field.model_name].append(field.name)
# convert default values to the right format
#
# we explicitly avoid using _convert_to_write() for x2many fields,
# because the latter leaves values like [(Command.LINK, 2),
# (Command.LINK, 3)], which are not supported by the web client as
# default values; stepping through the cache allows to normalize
# such a list to [(Command.SET, 0, [2, 3])], which is properly
# supported by the web client
for fname, value in defaults.items():
if fname in self._fields:
field = self._fields[fname]
value = field.convert_to_cache(value, self, validate=False)
defaults[fname] = field.convert_to_write(value, self)
# add default values for inherited fields
for model, names in parent_fields.items():
defaults.update(self.env[model].default_get(names))
return defaults
函数文档说的很清楚了,我在赘述一遍。
该函数根据传入的字段名返回响应的默认值,默认值是由context,用户定义以及模型本身决定的。
输入参数: field_list 字段名称列表。
返回值: 一个字典,key是字段名称,value是该字段的默认值
注意: 该函数只返回请求列表中的字段的默认值。至于有哪些字段,是由前端视图决定的。
从代码中可以看到,获取字典的默认值,按照优先级有四种方式:
action
<record id="action_move_out_invoice_type" model="ir.actions.act_window">
<field name="name">Invoices</field>
<field name="res_model">account.move</field>
<field name="view_mode">tree,kanban,form</field>
<field name="view_id" ref="view_out_invoice_tree"/>
<field name="search_view_id" ref="view_account_invoice_filter"/>
<field name="domain">[('move_type', '=', 'out_invoice')]</field>
<field name="context">{'default_move_type': 'out_invoice'}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a customer invoice
</p><p>
Create invoices, register payments and keep track of the discussions with your customers.
</p>
</field>
</record>
@api.model
def get(self, model_name, field_name, user_id=False, company_id=False, condition=False):
""" Return the default value for the given field, user and company, or
``None`` if no default is available.
:param model_name:
:param field_name:
:param user_id: may be ``False`` for all users, ``True`` for the
current user, or any user id
:param company_id: may be ``False`` for all companies, ``True`` for
the current user's company, or any company id
:param condition: optional condition that restricts the
applicability of the default value; this is an
opaque string, but the client typically uses
single-field conditions in the form ``'key=val'``.
"""
if user_id is True:
user_id = self.env.uid
if company_id is True:
company_id = self.env.company.id
field = self.env['ir.model.fields']._get(model_name, field_name)
default = self.search([
('field_id', '=', field.id),
('user_id', '=', user_id),
('company_id', '=', company_id),
('condition', '=', condition),
], limit=1)
return json.loads(default.json_value) if default else None
从代码看, 可以对模型中的某一字典,根据不同的用户、公司、条件设置不同的默认值。
但是实际开发中很少用。
这是最常见的设置默认值的一种方式
有三种设置方法:
1、 直接设置
active = fields.Boolean(default=True)
2、设置为一个函数
example_date = fields.Date(string='Date example', default=_default_example_date, store=False)
3 设置为lamda函数
user_id = fields.Many2one('res.users', default= lambda self: self.env.user)
关于委托继承,这里就不具体描述了。 简单理解就是数据存储在父表中,但是可以当自己的字段用。
通过一个many2one字段进行关联。
某些场景下,我们可以model中重写这个函数,加上我们自己的逻辑,比如:
def default_get(self, fields_list):
# 先调用父类方法
defaults = super().default_get(fields_list)
# 然后再执行自己的逻辑去对defaults 进行修改,最后再将它返回。
if 'journal_id' in defaults and 'date' in fields_list:
last_line = self.search([
('journal_id', '=', defaults.get('journal_id')),
('state', '=', 'posted'),
], limit=1)
statement = last_line.statement_id
if statement:
defaults.setdefault('date', statement.date)
elif last_line:
defaults.setdefault('date', last_line.date)
return defaults