Odoo 8 API – High Level
The Odoo 8 API introduced some novel concepts that provide a more object-oriented approach, significantly decreasing code repetition.
While these changes were definitely for the best, they created a major disparity between the two versions, and invalidated most of the code/tutorials that are available on the internet.
This article aims to highlight these changes, as well as provide some high level identification and conversion tactics.
Model ∞
The old API went through a lot of stages, but all of the old models are in some way contained within the osv
module.
Columns were defined using a _columns
dictionary as a class attribute, and utilize lowercase method names for the fields.
Old API Model Example:
from openerp.osv import osv, fields class my_model(osv.osv): _name = 'my.model' _columns = { 'my_column': fields.char(string='My Column') }
New models are much cleaner, and have the fields as directly defined class attributes.
You also don’t need to define a string attribute if a humanized, title case form of the column name fits the purpose (my_column
becomes My Column
).
Odoo 8 API Model Example:
from openerp import models, fields class MyModel(models.Model): _name = 'my.model' my_column = fields.Char()
Inheritance ∞
There are multiple inheritance mechanisms available for models.
You can use all of the mechanisms at once, if you so choose.
Check out this article for more information on inheritance mechanisms.
Model Inheritance Types:
class MyModel(models.Model): _inherit = 'my.model' #< Direct heritage _inherit = ['my.model', 'my.other.model'] #< Direct heritage _inherits = {'my.model': 'field_name'} #< Polymorphic heritage
If you define the name
attribute on an inherited model, you are creating a copy of the inherited model as a new model (and database table):
class MyModelNew(models.Model): _inherit = 'a.model' _name = 'my.model.new' new_field = fields.Char() #< This field isn't on the original model
Recordset ∞
All instances of Model are also instances of a Recordset.
A Recordset represents a sorted set of records of the same Model.
Pool vs. Env ∞
In the old API you would get the model from the pool, then perform an action on it:
partner_ids = self.pool('res.partner').search(cr, uid, [], context)
With the concept of an environment being introduced, you will now use that environment to get the model.
By using the environment, we are passing along the cr
, uid
, and context
without having to send them through to the method as arguments:
partner_ids = self.env['res.partner'].search([])
Old API Note ∞
The Old API always returned IDs of Recordsets, which then needed to be browsed on to actually utilize:
>> partner_ids = self.pool('res.partner').search(cr, uid, []) >> print partner_ids [1, 2, 3] #< partner_ids is an Array representing the Primary Keys of the Result >> partner_ids = self.pool('res.partner').browse(cr, uid, partner_ids) >> print partner_ids res.partner(1, 2, 3) #< partner_ids is now a Recordset of res.partners
The Odoo 8 API directly returns Recordsets, which is much more useful:
>> partner_ids = self.env['res.partner'].search([]) >> print partner_ids res.partner(1, 2, 3) #< partner_ids is a Recordset of res.partners of the Result
One gotcha, however, is that you cannot write a Recordset directly to the database or use it in search domains.
You instead need to generate a list of IDs representing the Primary Keys of the Recordset.
This is likely for compatibility, and I assume will get changed in the future (don’t quote me).
Odoo 8 API Domains:
partner_id = self.env['res.partner'].browse(1) user_id = self.env['res.users'].browse(1) # Correct write on `user_id.partner_id` user_id.write({ 'partner_id': partner_id.id, }) # Incorrect write on `user_id.partner_id` user_id.write({ 'partner_id': partner_id, }) ## The above fails because it is trying to directly write ## a Recordset to the DB
Environment ∞
In the Odoo 8 API, the concept of an Environment is introduced. Its main objective is to provide an encapsulation around the cursor, user_id, and context in relation to the Recordsets and Caches:
This concept greatly improved the Odoo design by providing a more Object Oriented approach.
Get the Context ∞
When using the old API, you could obtain the environment context with the method arguments.
In the Odoo 8 API, you can obtain the context via the Environment:
context = self._context # OR context = self.env.context
Modify the Environment ∞
The old method of changing the environment was to just pass an updated context via the method arguments.
The Odoo 8 API introduced a with_context method that accepts keyword arguments for contexts to add:
# Run a model under that context self.with_context(an_attribute=my_variable).my_method() # OR self.env['res.partner'].with_context(an_attribute=my_variable).my_method()
Or you can update the current context and pass it through instead:
# Copy the context to a dictionary that can be manipulated context = self._context.copy() # Add some things context.update({ 'default_user_id': user_id.id, }) # Run a model under that context self.with_context(context).my_method() # OR self.env['res.partner'].with_context(context).my_method()
Be careful not to modify the current RecordSet using this functionality:
self = self.env['res.partner'].with_context(context).browse(self.ids)
The above example will modify the current Records in the RecordSet after a re-browse, which will generate an incoherence between the caches and RecordSet.
Old Method Signature ∞
Old API method signatures include a cr
, uid
, and context
. Sometimes they also include id
or ids
.
cr ∞
This is the database cursor. For the most part, it is irrelevant while using newer api, but can still be accessed via the environment if needed:
cursor = self._cr # OR cursor = self.env.cr
uid ∞
This is the current user performing the operation. This can also be accessed via the environment if needed:
self.env.user
Changing the User ∞
The old API way of changing the user was to pass a different User record to the uid
param of the model method:
from openerp import SUPERUSER_ID ... def model_method(self, cr, uid, context=None): uid = SUPERUSER_ID self.other_model_method(cr, uid, context)
The Odoo 8 API cleaned this up quite a bit by the use of a new sudo
method:
self.sudo(user.id) self.sudo() # This will use the SUPERUSER_ID by default # Usage on another model: self.env['res.partner'].sudo().create(vals)
context ∞
This is the current environment context, which can now also be accessed via the environment:
self._context # OR self.env.context
See more about the context in Environment.
0