Creating grid views in Odoo

< / / / / / >
Skilled
Views
V13.0
V 13.0
+/- 16 minutes
Written by Yenthe Van Ginneken
(0)

Quick scroll

1. Introduction

The grid view is one of the most complex and flexible views in Odoo. It allows you to get a quick overview of a set of records at a specific point in time and gives you the possibility to bulk edit these records in one view. In this tutorial we will create a grid view for registering overwork to show you how the grid view works and what options are available. After this tutorial you will be able to create your own grid views and understand how the view works.

2. Adding the dependency

Before you can start creating grid views you will need to create a new module and configure the manifest.py correctly. Open up your manifest.py and add 'web_grid' as a dependency. As we'll use project tasks to link the overtime on also add a dependency to project:

                    'depends': ['web_grid', 'project'],                                    

Without the 'web_grid' dependency Odoo cannot build the view as 'web_grid' contains all the framework logic to build this view.

3. Creating the model

The first thing that we need is a model. Let's create a new file named 'work_overtime.py' in the 'models' folder of your custom module. Now create a new model named 'work.overtime' in this file. We'll add a few fields to have a minimal example for a grid view so let us link to a project, a task and create a date field and float for the duration to book the overtime on:

                    # -*- coding: utf-8 -*-from odoo import models, fields, api, _from odoo.osv import expressionclass WorkOvertime(models.Model):    _name = 'work.overtime'    _description = 'Contains the overtime logged by people'    name = fields.Char(string='Description', required=True)    project_id = fields.Many2one('project.project', string='Project', required=True)    task_id = fields.Many2one('project.task', string='Task')    date = fields.Date(string='Date', help='This date will be used in the grid view to define in'                                           ' which column the record should be shown.')    # Will be used to write the time (duration) on which is shown in the grid view.    unit_amount = fields.Float(string='Duration')                                    

Now that we have the model we should create a grid view in order to show all our records.

4. Creating the view

The grid view is not really the easiest view to build but don't worry, we'll go over it step by step. Have a look at this code example first:

                                                                                

As you can see the first part of the view definition is the same as other views. It is an XML record with a name, model and and arch. Within the arch you have a 'grid' in which the grid view is constructed. Let us look at this part line by line starting with the grid:

                                                                                

The grid tag needs at least a string value set. The adjustment and the adjustment_name are optional but if you want to add them you'll need both options as they work together. If you have no adjustment and adjustment name set you'll get the same grid view but with one big difference: you're not able to edit values in the grid view right away! We'll add the logic for the adjustment_grid later on in this tutorial. The next line is the project field:

                                                                                

The 'project_id' field will be shown as a row in the grid view thanks to the type="row" option. The section="1" will tell Odoo that you want to add the field to the first section of the view, all the way to the left. If you don't set it to the first section you'll get a pretty ugly and unformatted view. The following line task_id will also create a row but this time not with a section. Odoo now knows that you want to add the field 'project_id' in the first section of the view and as the field 'task_id' is under it Odoo will automatically show all tasks under the project. Fancy, no? Now comes the more complex part, the 'date' field:

                                                                                

When you set a field in the grid view with the type set to col Odoo will automatically show the value of the column as a cell in the header of the view (1). By default Odoo will also show the grid view in a weekly overview but what if you want to change this? By creating a range you will give the user the option to change the range of the grid view. In the above example it will add two buttons on the grid view named 'Week' and 'Month' (2) on which you can click and Odoo will automatically handle the timeframe you want to show on the grid view. At this point there are no other options than showing the grid view by week or month though, these are the only built in options.

Grid view example

The final part that you need is a field that contains a measure. In this tutorial we want to book overhours so we should add a float field that is shown as time (hh:mm):

                                                                                

This field will be shown as time in the grid view and will make every cell for every day editable. In order to be able to edit the values you will need to implement some Python code though. If you would now install this module you would not be able to edit any cell so let us continue and add the logic to directly edit cell values in the grid view!

4. Add logic to edit cells in grid view

Earlier in this tutorial we've added the 'adjustment' and 'adjustment_name' to the grid view:

                                                                                

The adjust_name 'adjust_grid' links to a Python function to execute code in the backend so we should add custom logic to handle the edits in a new Python function. Open up your model file 'work_overtime.py' again. We should now add this function with the logic to handle the edits. Let's go over this step by step. Start with a function and a check on the values in the cells::

                    def adjust_grid(self, row_domain, column_field, column_value, cell_field, change):    if column_field != 'date' or cell_field != 'unit_amount':        raise ValueError(            "{} can only adjust unit_amount (got {}) by date (got {})".format(                    self._name,                    cell_field,                    column_field,            ))                                    

The function takes 5 parameters by default:

  • row_domain: a dynamically built domain that filters out the current record.
  • column_field: the field name used for the column, in this tutorial it would be 'date'.
  • column_value: the datetime of the record you'd edit, for example 2019-03-18/2019-03-19.
  • cell_field: holds the name of the cell you've edited, in this tutorial it would be 'unit_amount'.
  • change: will hold the changed value from the edited cell.
The first part of the function should do a check if all values are correct as the value entered in the cell should match the field definition. If this is not a case it would return a ValueError which would mark the cell red (and would ignore the new value entered)

The next step is to handle the changing of existing lines. Imagine that you have booked two lines of overwork on one day for one task. It would create two records in the table 'work.overtime'. These two records however are combined in the grid view so if you would have one line with 5 hours and one line with 2 hours the grid view would show 7 hours. What if the user edits this number and changes 7 to 8? Odoo will not know where to handle this difference and what to write so we have to add logic for it:

                    day = column_value.split('/')[0]additionnal_domain = [('date', '=', day)]domain = expression.AND([row_domain, additionnal_domain])line = self.search(domain)day = column_value.split('/')[0]if len(line) > 1:  # copy the last line as adjustment    line[0].copy({        'name': _('Time Adjustment'),        column_field: day,        cell_field: change    })elif len(line) == 1:  # update existing line    line.write({        cell_field: line[cell_field] + change    })else:  # create new one - goess of when you directly fill in a time in a cell without the other fields    self.search(row_domain, limit=1).copy({        'name': _('Time Adjustment'),        column_field: day,        cell_field: change})                                    

This code handles the three possible cases. If there is more than one line related to a cell we will not know how to edit the existing lines so we will copy over the first line and just set a description 'Time adjustment' for the new line. If there is one line we can simply update the value of the line and if there is no line yet in a cell we will create a new line with the entered value with a custom description. Your final function should now look like this:

                    def adjust_grid(self, row_domain, column_field, column_value, cell_field, change):    if column_field != 'date' or cell_field != 'unit_amount':        raise ValueError(            "{} can only adjust unit_amount (got {}) by date (got {})".format(                    self._name,                    cell_field,                    column_field,            ))    day = column_value.split('/')[0]    additionnal_domain = [('date', '=', day)]    domain = expression.AND([row_domain, additionnal_domain])    line = self.search(domain)    day = column_value.split('/')[0]    if len(line) > 1:  # copy the last line as adjustment        line[0].copy({            'name': _('Time Adjustment'),            column_field: day,            cell_field: change        })    elif len(line) == 1:  # update existing line        line.write({            cell_field: line[cell_field] + change        })    else:  # create new one - goess of when you directly fill in a time in a cell without the other fields        self.search(row_domain, limit=1).copy({            'name': _('Time Adjustment'),            column_field: day,            cell_field: change    })                                    

5. Creating a security rule

Great job, the hardest part is done now! As we've created the model, the view and the logic to edit lines it is now time to create a security rule. Now add a security rule in 'ir.model.access.csv' to be able to access the view and create records in it. Let's create a simple security rule that gives all users full rights on the model 'work.overtime':

                    id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink--ENTER--access_work_overtime,work.overtime,model_work_overtime,,1,1,1,1                                    

6. Creating the menuitem and action to open it

Alright, we're almost done! Now that we have the model, the view and the security rule we just need a menuitem with an action in order to open the view(s). In this tutorial I'll create a new app on the homescreen with a configuration menuitem and an action as I do not know where you'd want to build these settings. You can just change this example.

6.1 Creating a main menuitem

First we'll need a main menu item, which will show up as an app on the Odoo home screen. Just create a new menuitem with a name and an icon:

                                                                                

6.2 Creating an action and submenu

The last step is to create an action and submenu. The action will make sure that if you click on the menuitem that it will open up our grid view:

                                                                                

Finally, add a child menuitem that is clickable and that also links to the action:

                                                                                

That's it! If you now install this module you'll have a fully working grid view.

7. Conclusion

Creating grid views in Odoo is not the easiest thing to do but the view offers you a lot of options. The grid view will allow you to see specific data from all records within a time range in one quick overview. By adding the 'adjustment' and 'adjust_name' options you'll also be able to quickly edit a big set of data from within one view. The grid view is a great view to get a clear overview of important data and being able to quickly edit it so it is totally worth the extra time to understand it.