La api de Odoo v8 (la misma que v9) pasó a usar recordsets en vez de usar sobretodo listas de id's (los identificadores del registro en la base de datos). Un recordset es una colección de elementos, de filas de la base de datos. Api v8 se olvida de estar gestionando listas de id's, lo cual hace la programación mucho más agradable.
@api.multi significa que la función esperará que el recordset pueda contener más de un elemento. Nunca deberías asumir que el recordset es único. Por eso es común en estas funciones ver esta estructura:
for order in self:
#codigo
Es decir, por cada elemento en el recordset haz #codigo.
@api.one confunde a mucha gente. No significa que solo se pueda llamar con un recordset único. @api.one es muy parecida a @api.multi en cuanto gestiona un recordset de varios elementos, solo que a la función, internamente, se la llama tantas veces como sea necesaria con una solo elemento del recordset cada vez hasta que se hayan procesado todos. Por ejemplo, si tienes un recordset de 3 elementos y lo usas para llamar a una función @api.one, lo que sucederá es que se llamará a esa función 3 veces, cada vez con un solo elemento. Si la función develueve algo (return res), se guardará cada return en una lista con el mismo orden que el recordset y se devolverá esa lista.
Basicamente @api.multi y @api.one son muy parecidos solo que @api.one es el código que hay dentro del loop for que recorre todos los elementos del recordset de @api.multi. El nombre de @api.one era lioso porque parece que requiera recordsets con un solo elemento, así que en la documentación de Odoo v9 se recomienda no usar y usar solo @api.multi.
Si requieres asegurarte que una función gestione un recordset de un solo elemento, por ejemplo para funciones que interactuan con las views, necesitas usar @api.multi con self.ensure_one(), así:
@api.multi
def mi_función(self):
self.ensure_one()
#codigo
@api.model es solo para poder interactuar adecuadamente con módulos que usen la API antigua. Básicamente @api.model hace esto:
@api.model
def mi_función(self, var1, var2):
la transforma si es necesario a api antigua de esta manera:
def mi_función(self, cr, uid, var1, var2, context=None):
Notese la diferencia con @api.multi, que equivale a esto:
@api.multi
def mi_función(self, var1, var2):
def mi_función(self, cr, uid, ids, var1, var2, context=None):
@api.multi incluye un recordset que se traduce en api antigua como una lista de id's.
Javier