5. Defaults, computations, and changes
Objectives
- distinguish default, on_change, Function, and stored fields
- keep client feedback consistent with server validation
- avoid expensive computed-field patterns
Mental model
Defaults initialize; on_change assists an unsaved form; Function fields compute or proxy values; validation protects every write path. User convenience is not data integrity.
Guided practice
- Set safe initial values with default_FIELD.
- Use depends metadata for fields read by on_change.
- Use Function only when computation or proxy semantics justify it.
- Provide a searcher when users must filter a computed value.
- Enforce the final invariant on the server.
Minimal example
from decimal import Decimal
from trytond.model import ModelSQL, ModelView, fields
class Book(ModelSQL, ModelView):
__name__ = 'library.book'
price = fields.Numeric("Price", required=True, digits=(16, 2))
discount = fields.Numeric("Discount", digits=(16, 2))
net_price = fields.Function(
fields.Numeric("Net Price", digits=(16, 2)),
'get_net_price')
@classmethod
def default_discount(cls):
return Decimal('0.00')
def get_net_price(self, name):
return (self.price or Decimal(0)) - (self.discount or Decimal(0))
How to read the example
For batches, prefer a class getter when it avoids one query per record. If net_price is searched frequently or must preserve history, a stored field updated by controlled logic may be a better design.
Exercise
Add a discount limit, immediate on-change feedback, and a server-side validation test that bypasses the client.
Run the exercise first with a minimal valid case, then add an invalid case and turn both into repeatable tests.
Verifiable result
The form reacts immediately, imports and RPC writes obey the same invariant, and listing 100 books does not cause an avoidable query per row.
Common mistakes
- putting security in on_change
- forgetting depends
- computing money with binary floats
- creating unsearchable Function fields used as filters
Ready-to-advance criteria
- I can explain the concepts without looking at the code.
- Valid and invalid cases have tests.
- I tested with a non-administrative user.
- I know how to upgrade and restore the training database.
Version and references
Series 8.0 requires at least Python 3.10 according to official metadata. The official server declares its project with pyproject.toml; new modules should use modern packaging and verify wheel contents. Do not confuse this historical minimum with the Python version certified by your organization.
This edition pins examples and dependencies to series 8.0. Check the official 8.0 tutorial, server API, and source branch before moving a pattern to production.