7 Computed fields: defaults and function fields
8 =============================================
10 The high-level API attempts to unify concepts of programmatic value generation
11 for function fields (stored or not) and default values through the use of
14 Fields are marked as computed by setting their ``compute`` attribute to the
15 name of the method used to compute then::
17 has_sibling = fields.Integer(compute='compute_has_sibling')
19 by default computation methods behave as simple defaults in case no
20 corresponding value is found in the database::
22 def default_number_of_employees(self):
23 self.number_of_employees = 1
29 has_sibling = fields.Integer(compute=fields.default(1))
31 but they can also be used for computed fields by specifying fields used for
32 the computation. The dependencies can be dotted for "cascading" through
35 @api.depends('parent_id.children_count')
36 def compute_has_sibling(self):
37 self.has_sibling = self.parent_id.children_count >= 2
43 has_sibling = fields.Integer()
45 @api.depends('parent_id.children_count')
46 def compute_has_sibling(self):
47 self.has_sibling = self.parent_id.children_count >= 2
49 note that computation methods (defaults or others) do not *return* a value,
50 they *set* values the current object. This means the high-level API does not
51 need :ref:`an explicit multi <fields-functional>`: a ``multi`` method is
52 simply one which computes several values at once::
54 @api.depends('company_id')
55 def compute_relations(self):
56 self.computed_company = self.company_id
57 self.computed_companies = self.company_id.to_recordset()
62 Using to the improved and expanded :ref:`computed fields <compute>`, the
63 high-level ORM API is able to infer the effect of fields on
64 one another, and thus automatically provide a basic form of onchange without
65 having to implement it by hand, or implement dozens of onchange functions to
75 partner = Partner.record(42, defer=True)
77 partner.user_id = juan
78 partner.save() # only saved to db here
81 # all records in this scope or children scopes are deferred
82 # until corresponding scope poped or until *this* scope poped?
83 partner = Partner.record(42)
85 partner.user_id = juan
86 # saved here, also for recordset &al, ~transaction
88 # temp deferment, maybe simpler? Or for bulk operations?:
89 with Partner.record(42) as partner:
91 partner.user_id = juan
93 ``id = False`` => always defered? null v draft?
95 .. todo:: keyword arguments passed positionally (common for context, completely breaks everything)
97 .. todo:: optional arguments (report_aged_receivable)
99 .. todo:: non-id ids? (mail thread_id)
101 .. todo:: partial signatures on overrides (e.g. message_post)
107 field = fields.Char()
117 field = fields.Char(compute='foo')
124 .. todo:: incorrect dependency spec?
126 .. todo:: dynamic dependencies?
132 self.a = self[self.b]
134 .. todo:: recursive onchange
136 Country & state. Change country -> remove state; set state -> set country
138 .. todo:: onchange list affected?