Monday, 9 February 2015

How related field work in Odoo 8, 9, and 10?


Let's take an example of Sale Order Line. Scenario is like when we add Product in sale order line at time, the Product Category name should be fill up. For that we need to do two  things.

  1. add related field in 'sale.order.line' and give it in view at proper place
  2. need to override onchange of product, if we don't want to override the onchange than at the time of record save it will also save the product category name.

Here is .py code:

Old API:

class sale_order_line(osv.Model):
    _inherit = 'sale.order.line'

    _columns = {
        'product_categ_name': fields.related('product_id', 'categ_id', 'name', type='char', string='Product Category', store=True, readonly=True),
}

New API:

from openerp import api, fields, models, _

class SaleOrderLine(models.Model)
    _inherit = 'sale.order.line'

    product_categ_name = fields.Char(related='product_id.categ_id.name', string='Product Category', store=True, readonly=True)

Here is .xml file

<?xml version="1.0" encoding="utf-8"?>
<openerp>
    <data>
   
        <record id="view_product_category_related_sale_line" model="ir.ui.view">
            <field name="name">view.product.category.related.sale.line</field>
            <field name="model">sale.order</field>
            <field name="inherit_id" ref="sale.view_order_form" />
            <field name="arch" type="xml">
                <xpath expr="//field[@name='order_line']/form/group/group/field[@name='product_id']" position="after">
                    <field name="product_categ_name"/>
                </xpath>
            </field>
        </record>

    </data>
</openerp>


Here is screen shot of it


More about on related field, take a look here

I hope you like this article. Share your views to improve content. Happy Learning !!!

Youtubde Video 

32 comments:

  1. Hi, I am facing a similar situation with pos.order.line, I would like to add name (pos.category, first choice) or categ_id (product_template) and create a filter based on it.
    Any clue on how to configure my fileds.related declaration?
    Thanks!

    ReplyDelete
    Replies
    1. You may declare related field as above given no issue in it. For filtering you need to inherit the search view of "pos_line" and add provide domain to it for example:

      domain = [('product_categ_name', '=', 'All Products')]

      Delete
    2. Thanks but probably I'm missing some dots... python newbie here!

      class pos_order_line (osv.Model):
      _inherit = 'pos.order.line'

      _columns = {
      'product_categ_name': fields.related('product_id', 'categ_id', 'name', type='char', string='Product Category', store=True, readonly=True ),
      }

      When I open the order menu Iget the error:

      ProgrammingError: column pos_order_line.product_categ_name does not exist
      LINE 1: ...e"."product_id","pos_order_line"."price_subtotal","pos_order...

      Delete
    3. you forgot to upgrade the module. Please upgrade it and than it will work.

      Delete
    4. I have update it. But for me worked just with
      'product_categ_name': fields.related('product_id', 'categ_id', 'name', type='char', string='Product Category', relation='product.template', store=True, readonly=True ),

      Anyway thanks for your sample, was very helpful!

      Delete
    5. Thank you.. Keep learning :-)

      Delete
    6. Odedra,
      I'm finding some issues doing the same thing adding partner_id to pos.orer.line. Since the key field is order_ref (and not product_id) what should be the correct syntax for fields.related?

      I've tried with
      'partner_id': fields.related('product_id', 'order_id', type='char', string='Customer', store=True, select=True, readonly=True),

      but didn't worked...

      File "/home/effe/odoo/openerp/models.py", line 5565, in __getitem__
      return self._fields[key].__get__(self, type(self))
      KeyError: 'order_id'

      And if I use name (as order ref is coded on pos.order) but the partner_id will replicate the name of the product.

      Any tips?

      Delete
    7. Your methodology is wrong, try with this,

      'partner_id': fields.related('order_id', 'partner_id', type='many2one', string='Customer', store=True, select=True, readonly=True),

      Delete
    8. Thanks for your help Odedra...
      probably I'm missing the concept here...

      class pos_order_line(osv.Model):
      _inherit = 'pos.order.line'

      _columns = {
      'product_categ_name': fields.related('product_id', 'categ_id', 'name', type='char', string='Product Category', store=True, select=True, readonly=True),
      'partner_id': fields.related('order_id', 'partner_id', type='many2one', string='Customer', store=True, select=True, readonly=True),

      Product_categ_name is working fine, but partner_id reports the internal code of res.partner, for example res.partner(6,). what is the correct name of the field I need to put in?

      Delete
    9. try with this,

      class pos_order_line(osv.Model):
      _inherit = 'pos.order.line'

      _columns = {
      'product_categ_name': fields.related('product_id', 'categ_id', 'name', type='char', string='Product Category', store=True, select=True, readonly=True),

      'partner_id': fields.related('order_id', 'partner_id', 'name', type='char', string='Customer', store=True, select=True, readonly=True),

      }

      Delete
  2. Odedra, thanks again for your time.

    Ok. This is my last attempt to resolve the issue. The field product_categ_id if correctly configured on pos.order (and/or pos.order.line) but there is a thing I didn't notice at first: adding this field broke the pos...

    maximum recursion depth exceeded
    (very long log here: http://pastebin.com/9Viwu4wa )
    RuntimeError: maximum recursion depth exceeded

    Probably the pos panel is triggering something more things of sale.order.
    Side note: I clear the browser's cache and reboot the server every time I made a modify of the DB.

    ReplyDelete
    Replies
    1. This error comes because of something wrong with Function field. This issue is not related with Related field. So advice to check function field. Just remove new function field if added and check it.

      Delete
  3. Sadly, there are no function fields added on my test_db. It's a plain stock with just the field product_categ_id... If I pull it out all works fine on module update.
    Again here how i've insert it on point_of_sale.py:

    class pos_order(osv.Model):
    _inherit = 'pos.order'

    _columns = {
    'product_categ_name': fields.related('product_id', 'categ_id', 'name', type='char', string='Product Category', store=True, readonly=True )
    }

    I've tried it with and without domain=[('product_categ_name', '=', 'All Products')] or relation='product.template'.

    ReplyDelete
    Replies
    1. Seems pos_categ_id from product.template is not affected. So far is working fine on my test db...

      Delete
  4. How do related fields work in one2many and many2many fields? For example, I am trying to show meeting attendee names on the calendar view. Calendar.event has both attendee_ids and partner.ids available, so partner.id.name doesn't work.

    By the way I am trying this using the new odoo 8 orm api.
    (i.e. "nickname = fields.Char(related='user_id.partner_id.name', store=True)"

    ReplyDelete
    Replies
    1. Functionality, related field which is related with one entity. If we give related field with one2many or many2many, it will confuse to pick value from the many entity. Generally, we are creating related field for information purpose. If you want to do display your custom value than you may go with function field.

      Delete
  5. Hi Odedra,

    I am new in python, I am facing similiar situation.
    I just want to viewed "default_code" field to "product" in "mrp_bom" form.
    So "product" view like this ["default_code" "name"].
    In my imagination :
    1. Add coloum "x_default_code" in mrp_bom table, related to "default_code" in product_product table.
    2. Modify "mrp_view.xml"

    This my code to add coloum

    _name = 'jn_mrp.bom'
    _description = 'Bill of Material Adding default_code field'
    _inherit = 'mrp.bom'

    _columns = {
    'xj_default_code': fields.related('product_id', 'default_code', type='char', relation='product.product', string='Part Number', store=True, readonly=True),

    }

    But the mrp_bom table same as before

    Please help

    ReplyDelete
    Replies
    1. Don't use _name for adding column on existing table. Because this will create a new table and you want to modify mrp_bom table.

      So use this simply,

      _description = 'Bill of Material Adding default_code field'
      _inherit = 'mrp.bom'

      _columns = {
      'xj_default_code': fields.related('product_id', 'default_code', type='char', relation='product.product', string='Part Number', store=True, readonly=True),

      }

      Delete
    2. share_id = fields.Integer('Flagged', related='product_id.ean13', store=True, readonly=True)

      not working

      Delete
    3. @Azhar, Ean13 field is a char field. So it should "Char" instead of "Integer"

      Try with following code.

      share_id = fields.Char(related='product_id.ean13', string='Flagged', store=True, readonly=True)

      Delete
  6. Hi Odedra!
    I'm trying to understand the concept of using related fields in v10. So here is the working example I did the other day:

    class add_to_customer_invoice(models.Model):
    _inherit = 'account.invoice'
    email = fields.Char(related='partner_id.email')

    It added 'email' fields from res.partner model to customer invoice form. But I don't understand how to build the chain ('partner_id.email').
    So let's say I want to take Expiration Date (validity_date) from 'sale.order' and add this field to 'account.invoice'. How to build the chain and what is the common rule to do this? I also want to create a new field in 'sale.order' and add it to 'account.invoice'. I think it'll be kinda the same as adding an existing field to other model. Thanks for help in advance!

    ReplyDelete
    Replies
    1. Yes you understand it correctly. We have to give/add Many2one(sale.order) field in account.invoice object. We can fill up new Many2one(sale.order) field id when invoice create from Sale order or Delivery order based on our Invoice control policy or Product setups. Afterwards you can declare your new field with related like Many2one(sale.order).validity_date. If you don't want to go with related field then we can override few existing method and fill up Expiration date in account.invoice object.

      Delete
    2. Thanks for response!
      So it'll be something like this?

      class AddToAccountInvoice(models.Model):
      _inherit = 'account.invoice'

      date_id = fields.Many2one('sale.order', 'Commitment Date')
      validity_date = fields.Date(related='date_id.validity_date')

      I get AssertionError: Document does not comply with schema.

      I'm still playing with the code, so hopefully will figure it out soon.

      Delete
    3. It seems code is correct. I am not sure what's wrong with that.

      Delete
  7. hi Bhavesh thank you for all your reply ... i have a problem with my related field , i have two classes : nomenclature and projet_ligne i want to get the value of ' sous' on 'eta' so there s my code

    class nomenclature(models.Model):
    _name = 'nomenclature'

    name = fields.Char('Nom de la nomenclature',required=True)
    quantite = fields.Integer('Quantité',required=True)
    produit=fields.Many2one('product.product')
    sous= fields.Boolean('sous')

    class projet_ligne(models.Model):
    _name = 'projet.ligne'
    nomenclature=fields.Many2one('nomenclature',required=True)
    responsable=fields.Many2one('res.users',)
    projet = fields.Many2one('projet',required=True)
    date= fields.Date()
    etat=fields.Boolean('Achevé?')
    reference= fields.Char('Réference')
    nature= fields.Char('Nature')
    dateprelevement= fields.Date()
    lieuprelevement= fields.Char('lieu')
    etatvalider= fields.Boolean('Validé')
    eta= fields.Boolean(related='nomenclature.sous')


    It doesn t work :/

    ReplyDelete
    Replies
    1. Set default value for sous= fields.Boolean('sous', default=False). Afterwards upgrade your module and try it. You will get value your value.

      Delete
  8. This comment has been removed by the author.

    ReplyDelete
  9. Hello, thanks a lot for your article !
    I'm on v9 and I'm a beginner with related fields, maybe you could solve my issue !
    Here's the context :
    Our company use the MRP module to craft a product X with products A, B, C, etc. I would like to display in the serial number of my product X : the sum of products consumed standard prices (can be A + B + C, A + C, or A + B + D ! That's why two products X can have a different cost, and I need to display it in the serial number).

    I succeed to add a field x_standard_price (with related field "product_id.standard_price") in the tree field "move_lines2" (correspond to the table "Products consumed" in the MO") so the total cost of A + B + C is displayed on the MO ! Great ! :)

    But I'm blocked to the final step : create a new field in the form view of serial numbers, which display what we have in "x_standard_price". But I don't know how to relate the field, how should I write it ? I don't know how it works so I tried random things like "move_id.x_standard_price", "move_lines2.x_standard_price", "product_id.x_standard_price", well I don't know what to write before "x_standard_price" ! :) Moreover, I can't deal with the code, I'm using the interface to create and edit my fields !

    If this issue seems obvious to solve to you, I would be very grateful for your help ! Regards,
    Fabien :)

    ReplyDelete
    Replies
    1. Hi Fabien,

      In your case, it is not easy to put related field in serial numbers form. First we need to find out key relation between Serial numbers and Stock moves objects.

      I would suggest you to make a function field.

      Function field logic will be to find key relationship.

      Delete
  10. Ok, thanks a lot for your feedback ! Now I know that's the key relation I have to find, I'll continue to dig around to find it :)

    ReplyDelete

ImportError: No module named googleapiclient

Recently, I have faced ImportError: No module named googleapiclient and I would like to share knowledge to fix that problem. Open termina...