|
| 1 | +=========================== |
| 2 | +Chapter 5: Connect the dots |
| 3 | +=========================== |
| 4 | + |
| 5 | +In this chapter, we'll add business logic to the models to automate the processes of our application |
| 6 | +and turn it into a dynamic and useful tool. This will involve defining actions, constraints, |
| 7 | +automatic computations, and other model methods. |
| 8 | + |
| 9 | +.. todo: explain the env (self.env.uid, self.env.user, self.env.ref(xml_id), self.env[model_name]) |
| 10 | +.. todo: explain magic commands |
| 11 | +.. todo: 6,0,0 to associate tags to properties in data |
| 12 | +.. todo: create (create offer -> offer received state) and write methods |
| 13 | +.. todo: auto-update property state based on received offers state (write) |
| 14 | +.. todo: best offer stat button |
| 15 | +.. todo: accepting offer refuses others |
| 16 | +
|
| 17 | +.. _tutorials/server_framework_101/computed_fields: |
| 18 | + |
| 19 | +Computed fields |
| 20 | +=============== |
| 21 | + |
| 22 | +.. todo: change section title |
| 23 | +
|
| 24 | +**Computed fields** are a special type of field that derive their value through programmatic |
| 25 | +computation rather than direct storage. The computation is performed on-the-fly by the server |
| 26 | +whenever the field is accessed. This makes computed fields highly convenient for tasks like |
| 27 | +displaying the results of calculations directly in views, automating repetitive processes, or
10000
td> |
| 28 | +assisting users with data entry. |
| 29 | + |
| 30 | +In Odoo, computed fields are implemented by defining a specific Python method and linking it to a |
| 31 | +field declaration using the `compute` argument. This method operates on a **recordset** :dfn:`a |
| 32 | +collection of records from the same model` represented by the `self` argument of the compute method. |
| 33 | +The method must iterate over the records to compute and set the field's value. When the computation |
| 34 | +depends on other fields, the method is decorated with :code:`@api.depends()`, which specifies the |
| 35 | +fields that should trigger an automatic recomputation whenever their value changes. |
| 36 | + |
| 37 | +.. todo: ref on recordsets |
| 38 | +.. todo: compute (offer deadline) |
| 39 | +.. todo: For relational fields, it’s possible to use paths through a field as a dependency: @api.depends('partner_id.name') |
| 40 | +.. todo: methods are private by default, meaning that they can't be called from the presentation |
| 41 | + tier, only from the business tier. See chap 1 |
| 42 | +.. todo: Although relational field names end with the `_id` or `_ids` suffix, variables holding a recordset of such fields |
| 43 | + are typically not suffixed. That is because, while the field represents the referenced record's id that is stored in the |
| 44 | + database, the variable is holding the full record in memory. |
| 45 | +
|
| 46 | +.. _tutorials/server_framework_101/inverse_computed_fields: |
| 47 | + |
| 48 | +Inverse computed fields |
| 49 | +----------------------- |
| 50 | + |
| 51 | +You might have noticed that computed fields are read-only by default. This is expected since the |
| 52 | +user is not supposed to set a value by themselves. |
| 53 | + |
| 54 | +.. todo: change section title |
| 55 | +
|
| 56 | +tmp |
| 57 | + |
| 58 | +.. todo: inverse (offer deadline) |
| 59 | +
|
| 60 | +.. _tutorials/server_framework_101/related_fields: |
| 61 | + |
| 62 | +Related fields |
| 63 | +-------------- |
| 64 | + |
| 65 | +.. todo: change section title |
| 66 | +
|
| 67 | +tmp |
| 68 | + |
| 69 | +.. todo: related fields (buyer's phone) |
| 70 | +
|
| 71 | +.. _tutorials/server_framework_101/stored_computed_fields: |
| 72 | + |
| 73 | +Stored computed fields |
| 74 | +---------------------- |
| 75 | + |
| 76 | +.. todo: change section title |
| 77 | +
|
| 78 | +tmp |
| 79 | + |
| 80 | +.. todo: implement search method |
| 81 | +.. todo: api.depends triggers a recomputation when update (already said above) |
| 82 | +
|
| 83 | +.. _tutorials/server_framework_101/onchanges: |
| 84 | + |
| 85 | +Onchange methods |
| 86 | +================ |
| 87 | + |
| 88 | +.. todo: change section title |
| 89 | +
|
| 90 | +**Onchange methods** are a feature of the server framework designed to respond to changes in field |
| 91 | +values directly within the user interface. They execute when a user modifies a field in a form view, |
| 92 | +even before saving the record to the database. This allows for real-time updates of other fields and |
| 93 | +provides immediate user feedback, such as validations, warnings, or suggestions. However, because |
| 94 | +onchange methods are only triggered by changes made in the UI, specifically from a form view, they |
| 95 | +are best suited for assisting with data entry and providing feedback, rather than implementing core |
| 96 | +business logic in a module. |
| 97 | + |
| 98 | +In Odoo, onchange methods are implemented as Python methods and linked to one or more fields using |
| 99 | +the :code:`@api.onchange()` decorator. These methods are triggered the specified fields' values are |
| 100 | +altered and operate on the in-memory representation of a single-record recordset received through |
| 101 | +`self`. If field values are modified, the changes are automatically reflected in the UI. |
| 102 | +Additionally, onchange methods can return non-blocking warnings or raise blocking errors to guide |
| 103 | +users during data entry. |
| 104 | + |
| 105 | + |
| 106 | +.. todo: raise UserError + translation |
| 107 | +.. todo: if garden checked -> show and compute total area |
| 108 | +
|
| 109 | +tmp |
| 110 | + |
| 111 | +.. _tutorials/server_framework_101/constraints: |
| 112 | + |
| 113 | +Constraints |
| 114 | +=========== |
| 115 | + |
| 116 | +.. todo: change section title |
| 117 | +
|
| 118 | +tmp |
| 119 | + |
| 120 | +.. _tutorials/server_framework_101/sql_constraints: |
| 121 | + |
| 122 | +SQL constraints |
| 123 | +--------------- |
| 124 | + |
| 125 | +tmp |
| 126 | + |
| 127 | +.. todo: price more than zero |
| 128 | +.. todo: unique tag constraint |
| 129 | +
|
| 130 | +.. _tutorials/server_framework_101/python_constraints: |
| 131 | + |
| 132 | +Python constraints |
| 133 | +------------------ |
| 134 | + |
| 135 | +tmp |
| 136 | + |
| 137 | +.. todo: accept only one offer |
| 138 | +
|
| 139 | +.. _tutorials/server_framework_101/defaults: |
| 140 | + |
| 141 | +Defaults |
| 142 | +======== |
| 143 | + |
| 144 | +.. todo: change section title |
| 145 | +.. todo: introduce lambda functions for defaults :point_down: |
| 146 | + also mention that `self` is evaluated as the current recordset in lambda functions |
| 147 | +
|
| 148 | +There is a problem with the way we defined our `Date` fields in the previous chapters: their default value relies on |
| 149 | +:code:`fields.Date.today()` or some other static method. When the code is loaded into memory, the date is |
| 150 | +computed once and reused for all newly created records until the server is shut down. You probably didn't |
| 151 | +notice it, unless you kept your server running for several days, but it would be much more visible with |
| 152 | +`Datetime` fields, as all newly created records would share the same timestamp. |
| 153 | + |
| 154 | +That's where lambda functions come in handy. As they generate an anonymous function each time they're evaluated |
| 155 | +at runtime, they can be used in the computation of default field values to return an updated value for each new record. |
| 156 | + |
| 157 | +.. todo: salesperson_id = fields.Many2one(default=lambda self: self.env.user) |
| 158 | +.. todo: real.estate.offer.amount::default -> property.selling_price (add related?) |
| 159 | +.. todo: real.estate.tag.color -> default=_default_color ; def _default_color(self): return random.randint(1, 11) (check if lambda works) |
| 160 | +.. todo: copy=False on some fields |
| 161 | +
|
| 162 | +.. _tutorials/server_framework_101/actions: |
| 163 | + |
| 164 | +Actions |
| 165 | +======= |
| 166 | + |
| 167 | +.. todo: change section title |
| 168 | +.. todo: "assign myself as salesperson" action |
| 169 | +.. todo: "view best offer" statbutton |
| 170 | +.. todo: accept/refuse offer buttons |
| 171 | +.. todo: action name=... |
| 172 | +
|
| 173 | +tmp |
| 174 | + |
| 175 | +.. _tutorials/server_framework_101/action_object: |
| 176 | + |
| 177 | +Object |
| 178 | +------ |
| 179 | + |
| 180 | +tmp |
| 181 | + |
| 182 | +.. _tutorials/server_framework_101/action_name: |
| 183 | + |
| 184 | +Name |
| 185 | +---- |
| 186 | + |
| 187 | +tmp |
| 188 | + |
| 189 | +.. _tutorials/server_framework_101/shell: |
| 190 | + |
| 191 | +Shell |
| 192 | +===== |
| 193 | + |
| 194 | +.. todo: change section title |
| 195 | +
|
| 196 | +tmp |
| 197 | + |
| 198 | +---- |
| 199 | + |
| 200 | +.. todo: add incentive for chapter 6 |
0 commit comments