Published: 2015-10-09

Using Odoo(about Model)

Table of Contents

1 Summary

This article is about tips, skills, mistakes I have met in the past working time. Odoo is a suite of web based open source business apps.(I copy from the README.md file). It is M-V-C strcture. The old name is Openerp. I use the old API, haven't transer to new API after Odoo 8.0 , developing on pyharm, which is a excellent IDE for python development. This is first article, about "Model".

Enviroment : odoo 8.0, python 2.7.6, postgresql 9.3.9, ubuntu 14.04

2 Config

I download odoo at odoo from github, let's call it directory odoo-8.0. Because I use ubuntu, you can find config file in odoo-8.0/debain/openerp-server.conf, so I copy this file to the root dir odoo8.0/, to configure it on my needs.Such as follows:

db_host = localhost
db_port = 5432
db_user = YourUserName
db_password = YourPassword
addons_path = addons,YourAddonsPathIfExist

Each time I need to to run server, add script parameters as follows:

Your/Path/To/odoo-8.0/odoo.py --config=Your/Path/To/odoo-8.0/openerp-server.conf

3 Module

ododd use Module to extend its funtion. when you need to ceate a module, you can create a folder in your addon directory, let's call it coolmodule. It needs two initial files : __init__.py and __openerp__.py. As the same for python pakages, you need to include files or direcotories in __init__.py. The __openerp__.py is use to config the module, as follows:

:::python

{
    'name': 'YourNameOfModule',
    'version': '0.0.1',
    'category': 'YourCategory',
    'sequence': '19',
    'description': """YourDescription""",
    'summary': u'YourSummary',

    'author': 'YourName',
    'website': 'YourWebsite',
    'depends': ['base','OtherDependsModules'],
    'data': [
            'coolmodule.xml',
            'security/ir.model.access.csv',
            'security/security.xml',
            'wizard/wizard_coolmodule.xml'
    ],
    'installable': True,
    'auto_install': False,
    'application': True,
}

Notice: above 'data: ['coolmodule.xml','security/ir.model.access.csv','security/security.xml','wizard/wizard_coolmodule.xml'] is some view and security files that you want to include in this module.

3.1 Model

Generally, the model file can be named as coolmodule.py (depends on you), the view file can be named as coolmodule.xml. In coolmodule.py, you can define model in this way(old api):

:::python

from openerp.osv import fields, osv

class cool_customer(osv.osv):
    _name = "cool.customer"
    _description = "YourDescriptions"

    def _default_title_id(self, cr, uid, context=None):
        #some code
        return title_id

    _columns = {
        'name' : fields.char('Name',required=True),
        'datetime': fields.datetime('DateTime'),
        'title': fields.many2one('cool.customer.title', 'Title'),
        'bank_ids': fields.one2many('cool.customer.bank', 'customer_id', 'Banks'),
        'comment': fields.text('Notes'),
        'active': fields.boolean('Active'),
        'type': fields.selection([('default', 'Default'), ('invoice', 'Invoice'),('delivery', 'Shipping'), ('contact', 'Contact'),('other', 'Other')], 'Address Type',help="SomeHelpText."),
        'category_id': fields.many2many('cool.costomer.category','coo_customer_category_rel', 'costomer_id', 'category_id', string='Tags'),
        #'display_name': fields.function(_display_name, type='char', string='Name', store=_display_name_store_triggers, select=True)
    }
    _defaults = {
        'datetime':fields.datetime.now,
        'active': True,
        'type': 'contact',
        'title': _default_title_id
    }


class cool_customer_title(osv.osv):
    _name = 'cool.custmoer.title'
    _order = 'name'
    _columns = {
        'name': fields.char('Title', required=True, translate=True),
        'shortcut': fields.char('Abbreviation', translate=True)
    }


class cool_customer_bank(osv.osv):
    _name = 'cool.customer.bank'
    _columns = {
        'name': fields.char('Title', required=True, translate=True),
        'code': fields.char('Code', size=64, required=True),
        'customer_id': fields.many2one('cool.customer', 'Account Owner', ondelete='cascade', select=True)
    }


class cool_customer_category(osv.osv):
    _name = 'cool.customer.category'
    _columns = {
    'name': fields.char('Category Name', required=True, translate=True),
    'customer_ids':fields.many2many('cool.costomer','coo_customer_category_rel', 'category_id', 'customer_id', string='Customers'),
    }
  • _name = 'cool.customer' This defines the name of this model, and the name(cool\customer) of table in database.
  • _columns = {...} This defines the columns of the table cool_customer, different types as above. Notes the funtion field is a little complicated, I decide to talk it after this article.
  • _defaults = {...} This defines the default value of columns or fields
  • colums 'datetime': fields.datetime('DateTime') This defines the date type, and there is an other tpye called fileds.date('Datet'), and you can use 'date': fields.date.today to set the default date to today
  • columns 'type': fields.selection([('default', 'Default'), ('invoice', 'Invoice'),('delivery', 'Shipping'), ('contact', 'Contact'),('other', 'Other')], 'Address Type',help"SomeHelpText."),= This defines a select coloums, when you have serverl certain options to pick, you can use this kind of field
  • many2one relation Just like 'title': fields.many2one('cool.customer.title', 'Title') to define a many2one relation
  • many2one relation The one side: 'bank_ids': fields.one2many('cool.customer.bank', 'customer_id', 'Banks') The many side: 'customer_id': fields.many2one('cool.customer', 'Account Owner', ondelete='cascade', select=True) ondelete='cascade': means if the record in one side is delete,what will do to the related many side? Other options are: 'null', default value is 'null'
  • many2many relation 'category_id': fields.many2many('cool.costomer.category','coo_customer_category_rel', 'costomer_id', 'category_id', string'Tags'),= The cool.costomer.category defines the relation model, the coo_customer_category_rel defines the third relation table name between the two models, 'category_id', 'customer_id' definds the columns in coo_customer_category_rel,notice the order to point right model. You can also not write coo_customer_category_rel, category_id', 'customer_id to let odoo name for you, but if you have lots many2many relations, remember to point clearly.
  • defaults : 'title': _default_title_id The default value of a field can also be a vale of funtion. Notice the definition of the function (such as _default_title_id here) should be above the place using it.

3.1.1 Methods: create, search, read, browse, write, unlink

  • create : when you need create a record, call this method, in this format: obj.create(cr, uid, vals, context=context)
    • vals is a python dictionary format such as {'name': YourName,'title':2,...}
    • obj is object or the model you want to create the record in. You can get obj like this: obj = self.pool.get('cool.customer').
    • The method returns the id of new record. If create unsucessfully, odoo will report error message.
  • search : this method is use to search the id(s) of given condition, like obj.search(cr, uid, domain,context=context)
    • domain is a list of tuple, which is some like `[('FieldName1','',Value1),('FieldName2','!',Value2)]``
    • This method returns a list of ids it finds, or a emppty list if no record finds.
  • read: this method is use to get a list of records of given fields.For

example, obj.read(cr,uid,ids,['fields1','fields2',...],context=context) - ids is a list of ids of records that you want to operate - 'fields1','fields2',... is fields or columns that you want to read, According to my previous project, it also add column id in the return fields. If you don't specific any field, it will read all the fields. - This method return something like this: [{'id':1,fields1': value1,'fields2': value2,...}, {...}, ...]

  • browse: It is use to get a specific instance of object. For example, you can use obj = self.pool.get('cool.customer') to get a object(or in java terms,a class) of 'cool.customer', and use instance_obj = obj.browse(cr,uid,ids,context=context) to get specific ids of objs. It just like 'class' and 'instance' relations (in java terms). Or maybe, call the value of self.pool.get('cool.customer')' 'class' is more accurate. The advantage is you can use such as instance_obj.name to get the name of this specific object.
  • write: This method is use to change values of specific records. Format: obj.write(cr,uid,ids,vals,context)
    • ids is a list of ids you want to change
    • vals is a python dictionary, like {'FieldName1':vale1,'FieldName2':value2,...}, Notice,if your Filed is one2many type, just like example field above: bank_ids, the value is a list of tuple, depends on different change ways, tuple format is different. And if this field is many2many type,the tuple is also different,like follows:
      :::python
      ##one2many
      #Add new record
      (0, 0,{ values })
      
      #update the record which id equals ID
      (1,ID,{values})
      
      #Delete the record which id equals ID
      (2,ID)
      
      ##many2many
      #Add new record
      (0, 0,{ values })
      
      #update the record which id equals ID
      (1,ID,{values})
      
      #Delete the record which id equals ID (call unlink method)
      (2,ID)
      
      #Cut off relationship, but leave the data
      (3,ID)
      
      #Link the relation of record which id equals ID
      (4,ID)
      
      #Cut off all relations
      (5)
      
      #Cut off all relations and Use records in IDs to replace  
      #This is confusing :(, I will add examples in the following articles
      (6,0,[IDs])
      
    • This method returns True or raise exception
  • unlink : This method is use to delete record(s), format: obj.unlink(cr,uid,ids,context)
    • ids is a list of ids of records you want to delete
    • This method returns True or raise exception

Notice:

  • if you use instanceofobject, in other words, you use the

obj getting from methods browse, no need to write "cr, uid" or "ids" due to conditions.

  • We can also rewrite the model's "write", "create"

or other function. This will be talk about later

3.1.2 Methods: defaultget, defaultset

To be continue here:)

3.1.3 Error Info for User

raise osv.except_osv(_('Error!'), _('Error Message.'))

Author: Nisen

Email: imnisenATgmailDOTcom

Emacs 25.2.1 (Org mode 8.2.10)