Search code examples
mappingfieldodooxml-rpcmany-to-one

How to write fields many2one in Odoo with XMLRPC


I want to use the xmlrpc for the model "product.category".

How to write the field "categ_id" with "read and search"in PYTHON ? I have always an error. I need to do that because i have to transfer this informations into another database Odoo.

    import xmlrpc.client
    import time
    url_db1="http://localhost:8069"
    db_1='DB_ONE'
    username_db_1='username'
    password_db_1='password'

    common_1 = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url_db1))
    models_1 = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url_db1))
    version_db1 = common_1.version()

    print("details..", version_db1)


    url_db2="http://localhost:806972"
    db_2='DB_2'
    username_db_2='myemail'
    password_db_2='mypassword'

    common_2 = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url_db2))
    models_2 = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url_db2))
    version_db2 = common_2.version()

    print("details..", version_db2)


    uid_db1 = common_1.authenticate(db_1, username_db_1, password_db_1, {})
    uid_db2 = common_2.authenticate(db_2, username_db_2, password_db_2, {})

    db_1_categories = models_1.execute_kw(db_1, uid_db1, password_db_1, 'product.category', 'search_read', [[]], {'fields':['id','name', 'parent_id']})

    total_count = 0
    for category in db_1_categories:
        print("category..", category)
        total_count +=1
        values = {}
        values['id'] = category['id']
        values['name'] = category['name']
        if category['parent_id']:
            values['parent_id'] = category['parent_id'][0]
        new_lead = models_2.execute_kw(db_2, uid_db2, password_db_2, 'product.category', 'create', [values])
print("Total Created..", total_count)

This is the error : ValidationError: ('The operation cannot be completed: another model requires the record being deleted. If possible, archive it instead.\n\nModel: Product Category (product.category), Constraint: product_category_parent_id_fkey', None)\n'>

enter image description here


Solution

  • The method name should be search_read

    Example:

    models.execute_kw(db, uid, password,
       'product.template', 'search_read',
        [],
        {'fields': ['name', 'default_code', 'categ_id']})
    

    It should return a list of dicts, the categ_id field value is a list of two values, the first is the id of the category and the second is the name of the category.

    To write categ_id, you just need to provide the category ID to the write method.

    Example:

    product_template_data = [{'default_code': 'FURN_6666', 'categ_id': [8, 'All / Saleable / Office Furniture'], 'id': 23, 'name': 'Acoustic Bloc Screens'}, ...] 
    
    for ptd in product_template_data:
        models.execute_kw(db, uid, password, 'product.template', 'write', 
            [[ptd['id']], 
            {
                'categ_id': ptd['categ_id'][0],
                ...
            }
        ])
    

    You mentioned that you need to transfer data to another database, the product template is probably not present which means that you can't call the write method instead, you can call the create method.

    Example:

    id = models.execute_kw(db, uid, password, 'product.template', 'create', [{
        'categ_id': ptd['categ_id'][0],
        ...
    }])  
    
    

    Edit:
    You will get an invalid syntax error using:

    [product,'categ_id': product['categ_id'][0],]
    

    To pass values to the create method, you need to pass args to the execute_kw method as a list then pass values as a dictionary inside that list.

    Edit:

    
    values = {}
    values['name'] = product['name']
    values['categ_id'] = product['categ_id'][0]
    ...
    new_lead = models_2.execute_kw(db_2, uid_db2, password_db_2, 'product.template', 'create', [values])
    

    Edit: Use the parent category id in the new database

    When we call the create method it will create a new record and return its ID which is probably different the one passed through the values dictionary.

    To avoid the ValidationError you can use a dictionary where the parent ID in the old database is the key and the new ID is the value then you have just to pass that value when creating a new category.

    category_ids = {}
    for category in db_1_categories:
            print("category..", category)
            total_count +=1
            values = {}
            # values['id'] = category['id']
            values['name'] = category['name']
            if category['parent_id']:
                values['parent_id'] = category_ids[category['parent_id'][0]]
            category_id = models_2.execute_kw(db_2, uid_db2, password_db_2, 'product.category', 'create', [values])
            category_ids[category['id']] = category_id