In Odoo once an XML view is defined we don’t have much possibility to change it dynamically depending on other fields. Consider the case where we want to change the label or string of a field depending on another field. Moreover in the XML definition we cannot do this dynamically however, using fields_view_get we can dynamically change the label or string of the field.
This can be achieved by overriding the fields_view_get function of the models the Model class. Moreover, the model class is called every time a model is rendered in Odoo.
Consider the scenario where we want to update the string or label of a field dynamically. Let’s see how we can do that without changing the XML code. Furthermore in order to change a string or label dynamically of a field or a record, we have to override the corresponding fields_view_get method of that model.
Therefore, our model class is considered to be SalePackageBundle which contains details about the different package bundles corresponding to a sale order.
The above image depicts the basic form view of the package bundle. Let’s say that we have to change the string of the Sale Reference to a custom string. This example might feel odd, but with a similar method we can dynamically change the string or label of a field.To do so we should initially call the fields_view_get inside our corresponding model class.
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
The fields_view_get method takes different parameters:
- self: Current record details or None value
- view_id: The id of the corresponding view(tree, form, kanban etc)
- view_type: The type of view with which we are dealing
- toolbar, submenu: If any, can be specified here, but their presence is necessary so we set the value to False.
result = super(SalePackageBundle, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
Next we call the existing fields_view_get method of the model and we’ll tinker with its result. Therefore, we called the super method of the SalePackageBundle’s fields_view_get method with the parameters as passed. Now considering our scenario where we want to change the string of the existing field, Sale Reference.
Since our model currently has only a single form and tree view, we can directly check the condition as to whether the view_type == ‘form’ or view_type == ‘tree’. There might be cases where the model with which we are dealing may contain more than one form or other views. In that case we can use the condition with the view_id, as with each view its view_id will be unique.
As we are changing the string for a field inside our form view, we give the condition as:
if view_type == 'form':
Next we fetch the corresponding XML for the form view. For that add the following import and load the XML into a variable.
from lxml import etree
doc = etree.XML(result['arch'])
The XML corresponding to the form view is loaded into the variable, doc.
Next we obtain the corresponding field to which we are changing the string value.
sale_reference = doc.xpath("//field[@name='sale_order_name']")
‘sale_order_name’ is the field name for the Sale Reference.
In order to change the string value of the field, we use the set method.
sale_reference[0].set("string", "Sale Order")
Please keep in mind to call the field with [0], as the field value is part of a list.
Inside the set method, we pass the attribute to which we are setting the value, in our case its the string and the next attribute takes its value, i.e. Sale Order.
Further, we’ll pack the modifications we have done and load that into our result string.
result['arch'] = etree.tostring(doc, encoding='unicode')
return result
The results will be that the string is changed from Sale Reference to Sale Order in our form view. As the fields_view_get method is called only during the initial rendering, we have to reload the view each time to view the changes that we have made.
It can be viewed upon reload that the string has been changed to Sale Order.
Similarly, if we want to add a label to the field, we can do that by using the addnext method.
sale_reference[0].addnext(etree.Element('label', {'string': 'Sale Reference Number'}))
The value of the string key will be displayed as a label under the field.
The complete code is given below:
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
result = super(SalePackageBundle, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
if view_type == 'form':
doc = etree.XML(result['arch'])
sale_reference = doc.xpath("//field[@name='sale_order_name']")
if sale_reference:
sale_reference[0].set("string", "Sale Order")
sale_reference[0].addnext(etree.Element('label', {'string': 'Sale Reference Number'}))
result['arch'] = etree.tostring(doc, encoding='unicode')
return result
This example might not seem meaningful, but using a similar method we can change the label or string of fields dynamically depending on different conditions and different types of views.