Changing existing views: View inheritance

Up until now, we ignored the existing views and declared completely new ones. While this is didactically sensible, you'll rarely be in situations where you want to define a new view for an existing model. What you'll rather want to do is to slightly modify the existing views, be it to simply have it show a field you added to the model in your addon, or to customize it to your needs or your customer's.

In this recipe, we'll change the default partner form to show the record's last modification date and also allow searching for that. Then we'll also show this column in the partners' list view.

How to do it...

  1. Inject the field in the default form view:
    <record id="view_partner_form" model="ir.ui.view">
        <field name="model">res.partner</field>
        <field name="inherit_id" ref="base.view_partner_form" />
        <field name="arch" type="xml">
            <field name="website" position="after">
                <field name="write_date" />
            </field>
        </field>
    </record>
  2. Add the field to the default search view:
    <record id="view_res_partner_filter" model="ir.ui.view">
        <field name="model">res.partner</field>
        <field name="inherit_id" ref="base.view_res_partner_filter" />
        <field name="arch" type="xml">
            <xpath expr="." position="inside">
                <field name="write_date" />
            </xpath>
        </field>
    </record>
  3. Add the field to the default list view:
    <record id="view_partner_tree" model="ir.ui.view">
        <field name="model">res.partner</field>
        <field name="inherit_id" ref="base.view_partner_tree" />
        <field name="arch" type="xml">
            <field name="email" position="before">
                <field name="write_date" />
            </field>
        </field>
    </record>

After updating your module, you should see the extra field Last updated on beneath the website field on the partner form. When you type in something that looks like a date (a digit or two) in the search box, it should propose to search for partners last modified on this date, and in the partner's list view, you should see the modification date left of the e-mail column.

How it works...

The crucial field here is, as you probably have guessed, inherit_id. You need to pass it the XML ID of the view you want to modify (inherit from), and the arch field then contains instructions on how to modify the existing XML nodes within the view you're inheriting from. You actually should think of the whole process as quite simple XML processing, because all the semantic parts come only a lot later.

The most canonic instruction within the arch field of an inherited view is the field element, which has the required attributes name and position. Because you can have every field only once on a form, the name already uniquely identifies a field, and with the position attribute, we can place whatever we put within the field element either before (1), inside (2), or after (3) the field we named. The default is inside, but for readability you should always name the position you mean. Remember that we're not talking semantics here; this is about the position in the XML tree relative to the field we have named. How this will be rendered afterwards is a completely different matter.

Example 2 above demonstrates a different approach. The xpath element selects the first element matching the XPath expression named in the attribute expr. Also, here the position attribute tells the processor where to put the xpath element's contents.

XPath might look somewhat scary, but is a very efficient means of selecting the node you need to work on. Take the time to look through some simple expressions, it's worth it. Probably in the tutorials you'll find, you'll stumble upon the term context node to which some expressions are relative. In Odoo's view inheritance, that's always the root element of the view you're inheriting from.

For all the other elements found in the arch field of an inheriting view, the processor looks for the first element with the same node name and matching attributes (with the attribute position excluded, as this is part of the instruction). Use this only in cases where it is very improbable that this combination is not unique, like a group element combined with a name attribute.

Tip

Note that you can have as many instruction elements within the arch field as you need. We only used one per inherited view because there's no more we currently want to change.

There's more...

The position attribute has two other possible values: replace and attributes. Using replace causes the selected element to be replaced with the content of the instruction element. Consequently, if you don't have any content, the selected element is simply removed. In the list or form view above would cause the email field to be removed.

<field name="email" position="replace" />

Note

Removing fields can cause other inheriting views to break and several similarly ugly side effects, so avoid that if possible. If you really need to remove fields, do so in a view which comes late in order of evaluation (see next).

Using attributes has a very different semantics from all of the above. The processor then expects the element to contain the attribute elements with a name attribute. Those elements will then be used to set attributes on the selected element. If you want to heed the warning from above, you'd better set the invisible attribute to 1 for the email field:

<field name="email" position="attributes">
    <attribute name="invisible">1</attribute>
</field>

Order of evaluation in view inheritance

Because we have only one parent view and one inheriting view, we don't run into any problems with conflicting view overrides. When you have installed a couple of modules, you'll find a lot of overrides for the partner form. This is all fine as long as they change different things in a view, but there are occasions where it is important to understand how the overriding works in order to avoid conflicts. Direct descendants of a view are evaluated in ascending order of their priority field, so views with a lower priority are applied first. Every step of inheritance is applied to the result of the first, so if a view with priority 3 changes a field and another one with priority 5 removes it, things are fine, but they break if the priorities are reversed.

Then you can also inherit from a view that is itself an inheriting view. In this case, the second level inheriting view is applied to the result of the view it inherits from. So, if you have four views A, B, C, and D, where A is a standalone form, B and C inherit from A, and D inherits from B, the order of evaluation is A, B, D, C. Use this to enforce an order without having to rely on priorities; that's safer in general. Especially if some inheriting view adds a field and you need to apply changes to this field, inherit from the inheriting view and not from the standalone one.

Note

This kind of inheritance always works on the complete XML tree from the original view, with modifications from the previous inheriting views applied.

See also

For inheriting views, a very useful and not very well known field is groups_id. This field causes the inheritance to take place only if the user requesting the parent view is member of one of the groups mentioned there. This can save you a lot of work when adapting the user interface for different levels of access, because with inheritance you can have more complex operations than just showing or not showing the elements based on group membership, as is possible with the groups attribute on form elements as discussed earlier. You can for example remove elements if the user is member of some group (which is the inverse of what the groups attribute does), but also some quite elaborate tricks like adding attributes based on group membership, think about simple things like making a field read only for certain groups, or more interesting ones like using different widgets for different groups.

What was described here is the case if the mode field of the original view is set to primary, while the inheriting views have mode extension, which is the default. We'll look into the case that mode of an inheriting view is set to primary later, where the rules are slightly different.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.216.12