Python中值变化时触发函数的实现方法及Odoo假期池计算方法修改需求
Depending on your scenario, there are a few practical ways to achieve this:
Using Python Properties
For simple class attributes, properties are the most straightforward approach. You can define a setter that checks if the new value differs from the old one, then fires your target function:
class MyClass: def __init__(self): self._value = None @property def value(self): return self._value @value.setter def value(self, new_val): if new_val != self._value: self._value = new_val self._on_value_change() def _on_value_change(self): print("Value updated! Triggering related logic...")
Observer Pattern
If multiple components need to react to value changes, the observer pattern is ideal. It lets you register "observers" that get notified whenever the value updates:
class ObservableValue: def __init__(self): self._observers = [] self._current_value = None @property def value(self): return self._current_value @value.setter def value(self, new_val): if new_val != self._current_value: self._current_value = new_val self._notify_observers() def add_observer(self, observer): self._observers.append(observer) def _notify_observers(self): for observer in self._observers: observer.on_value_update(self._current_value) class ValueObserver: def on_value_update(self, value): print(f"Received updated value: {value}") # Example usage my_value = ObservableValue() observer = ValueObserver() my_value.add_observer(observer) my_value.value = 42 # Triggers the observer's update method
Odoo-Specific Methods
Since your second question relates to Odoo, here's how to handle field changes in the Odoo ecosystem:
- Computed Fields: Use the
@api.dependsdecorator to trigger a computed method when specific fields change. - Override Write: Override the
writemethod to compare old and new field values, then run your logic if a change is detected. - Tracking: Add
tracking=Trueto a field to log changes, then react to those logs in related methods.
Let's break down your requirement: you want to skip action when annual_leave changes, but increment remaining_count (from your holiday pool) when it doesn't. Here's how to adjust your code:
Assumptions
annual_leaveis a field on your model (we'll cover an alternative if you meant the annual holiday count from the search below).- You want to add 1 to
remaining_countwhen settingcurrent_holiday_poolonly ifannual_leavehasn't changed.
Step 1: Update the Depends Decorator
First, ensure your computed method triggers when annual_leave changes by adding it to the @api.depends list:
@api.multi @api.depends('yearly_holidays_ids', 'annual_leave') # Add annual_leave here def _get_current_holiday_pool(self):
Step 2: Check for Changes and Adjust Logic
Use Odoo's has_changed method to detect if annual_leave was modified in the current write operation. Then adjust the current_holiday_pool calculation accordingly:
from odoo import api, models, fields import datetime class YourModel(models.Model): _name = 'your.model.name' # Replace with your actual model name annual_leave = fields.Integer(string='Annual Leave') current_holiday_pool = fields.Float(compute='_get_current_holiday_pool', store=True, string='Current Holiday Pool') yearly_holidays_ids = fields.One2many('yearly.holidays', 'related_model_id', string='Yearly Holidays') @api.multi @api.depends('yearly_holidays_ids', 'annual_leave') def _get_current_holiday_pool(self): for record in self: # Skip logic if annual_leave changed in this write if record.has_changed('annual_leave'): continue current_year = datetime.date.today().year total_holidays = record.yearly_holidays_ids.filtered(lambda lm: lm.year == current_year) annual_leaves_count = self.env['hr.holidays'].search_count([('holiday_status_id.name', '=', 'annual')]) if annual_leaves_count > 1: if total_holidays: record.current_holiday_pool = total_holidays[0].remaining_count + 1 elif annual_leaves_count == 1: if total_holidays: record.current_holiday_pool = total_holidays.remaining_count + 1 else: record.current_holiday_pool = 0
Alternative: If annual_leave refers to the search count
If you meant the annual_leaves_count from the search_count call instead of a model field, you'll need to store the previous count to compare. Add a field like last_annual_leaves_count to track it:
last_annual_leaves_count = fields.Integer(string='Last Annual Leaves Count', store=True) @api.multi @api.depends('yearly_holidays_ids') def _get_current_holiday_pool(self): for record in self: current_year = datetime.date.today().year total_holidays = record.yearly_holidays_ids.filtered(lambda lm: lm.year == current_year) annual_leaves_count = self.env['hr.holidays'].search_count([('holiday_status_id.name', '=', 'annual')]) # Compare current count with stored last count if annual_leaves_count != record.last_annual_leaves_count: record.last_annual_leaves_count = annual_leaves_count continue # Increment remaining_count since the count didn't change if annual_leaves_count > 1: if total_holidays: record.current_holiday_pool = total_holidays[0].remaining_count + 1 elif annual_leaves_count == 1: if total_holidays: record.current_holiday_pool = total_holidays.remaining_count + 1 else: record.current_holiday_pool = 0
Key Notes
- The
has_changedmethod only works during write operations; use a stored field if you need to track changes across sessions. - Always handle empty
total_holidaysto avoid AttributeErrors. - Add
store=Truetocurrent_holiday_poolif you want to persist the computed value.
内容的提问来源于stack exchange,提问作者SaltySteven

