Odoo11中write与update方法的区别及write仅首次生效问题咨询
write() and update() + Fixing the "One-Time write()" Bug Hey there! Let's tackle your two questions head-on—first, clarifying the key differences between Odoo's write() and the Python update() methods, then troubleshooting why write() might only work once for you.
Core Differences Between write() and update()
These two methods look similar on the surface, but they operate in completely different ways:
ORM vs. Dictionary Method:
write()is an official Odoo ORM method designed for persistent record updates. It works on an existing recordset (likeself.env['res.partner'].browse(1)), triggers all built-in Odoo logic—think field validation,onchangehooks, post-write signals, and even overriddenwrite()methods in parent models. It’s the "proper" way to update records in Odoo.update()is a standard Python dictionary method, not part of Odoo's ORM. It only modifies the in-memory cache of your recordset—no database writes, no validation, no triggers. If you don’t follow it up withflush()orsave(), those changes vanish as soon as the recordset goes out of scope.
Database & Relational Field Handling:
write()immediately commits changes to the database (unless you’re in a rolled-back transaction) and correctly handles relational fields likemany2manyorone2manyby updating their associated junction tables.update()doesn’t touch the database at all. It can’t handle relational fields properly either—setting amany2manyfield viaupdate()will just mess up the cache, not the actual database relations.
Error Handling & Safety:
write()will throw an error if you miss required fields, use invalid values, or don’t have permissions to edit the record. This is a good thing—it keeps your data consistent.update()skips all checks. You can set invalid values or even protected fields without getting an error… until you try to flush those changes, at which point you’ll hit a wall.
When to Use Which:
- Use
write()for almost all persistent record updates—this is the method Odoo expects you to use for standard business logic. - Use
update()only for temporary in-memory tweaks (like preparing data before a bulkwrite()for performance) and only if you’re confident you understand the cache implications.
- Use
Troubleshooting: write() Works Once, Then Fails
This is a super common gotcha in Odoo, usually tied to recordset immutability or transaction/cache issues. Let’s walk through the most likely fixes:
1. You’re Using a Stale Recordset
Odoo recordsets are immutable. When you call write() on a recordset, it returns a new, updated recordset. If you keep using the original variable, it’s pointing to stale data—so your second write() might be hitting an outdated or empty recordset.
Mistake Example:
partner = self.env['res.partner'].browse(1) partner.write({'name': 'First Update'}) # Wrong: reusing the old, stale partner variable partner.write({'name': 'Second Update'}) # Won't work as expected
Fix:
Reassign the recordset after each write(), or refetch it to get fresh data:
# Option 1: Reassign the returned recordset partner = self.env['res.partner'].browse(1) partner = partner.write({'name': 'First Update'}) partner.write({'name': 'Second Update'}) # Option 2: Refetch the record to ensure freshness partner = self.env['res.partner'].browse(1) partner.write({'name': 'First Update'}) partner = self.env['res.partner'].browse(1) partner.write({'name': 'Second Update'})
2. Transaction Rollbacks Are Undoing Changes
If your first write() is part of a transaction that gets rolled back (e.g., an exception occurs after the write but before the transaction commits), your second write() is working on stale data. Check for hidden exceptions—Odoo automatically rolls back transactions when unhandled errors pop up.
For custom scripts or long-running processes, use savepoints to protect against rollbacks:
with self.env.cr.savepoint(): partner.write({'name': 'First Update'}) # If an error occurs here, it only rolls back to the savepoint, not the entire transaction partner.write({'name': 'Second Update'})
3. Permissions or Record Rules Blocking Subsequent Writes
After the first write, might the record’s state have changed in a way that your user loses write access? For example, a record rule (ir.rule) that blocks editing once a record is marked "completed".
Test this by bypassing permissions temporarily with sudo():
partner.sudo().write({'name': 'Second Update'})
If this works, you’ll need to adjust your record rules or user permissions to allow edits after the first update.
4. An Overridden write() Method Is Blocking Edits
If your model inherits from another model that overrides write(), that parent method might have conditional logic that prevents subsequent writes. For example, a parent model could restrict edits once a certain state is set, and your first write triggers that state change.
Check the parent models’ write() implementations for conditions like if self.state == 'done': return True—that would stop any further writes. You can override the method yourself to adjust this logic if needed.
5. Cache Inconsistencies Are Causing Stale Data
If you’re mixing write() with update() or direct SQL queries, Odoo’s cache can get out of sync. Force a cache refresh with invalidate_cache() to ensure you’re working with fresh data:
partner.write({'name': 'First Update'}) self.env['res.partner'].invalidate_cache() partner = self.env['res.partner'].browse(1) partner.write({'name': 'Second Update'})
内容的提问来源于stack exchange,提问作者user_123

