Enable Dark Mode!
how-create-module-odoo.png
By: Niyas Raphy

How to Create a Module in Odoo?

Technical Odoo 10

For those who are in the starting stage of Odoo development, it is a tough task for creating a new module. In this section let us look at how to create a new module in the Odoo.
There are mainly four files required for creating a new module (.py or .xml can be excluded as per the need).
The main four files are,
* __init__.py
* __manifest__.py
* model.py
* view.xml
This is based on v10, in the v9 and v8, we have to use __openerp__.py instead of the __manifest__.py. The above four files should be inside a folder, let the folder name be the school
__init__.py
In the __init__.py file, we have to import all the python files that we are going to use. Suppose as described above we have a python file called model.py in our module. The first thing we have to do is, import the model.py in the __init__.py file.
So our __init__.py file will be like this, 
import model
__manifest__.py
In the __manifest__.py, We have to mention the module name, the author name, version, description, company, category, etc. Now let us see what all these things for,
* Name – Name of the module to be displayed
* Author – The name of one who created the module
* Version – version of the released module, is it v10,v9 or v8
* company – The company which developer module
* website – the website address of the company
* Category – Category of the module, whether it is sales, purchase, the point of sale etc.
* depends – Suppose if our module depends on any other modules, we have to mention that name in the depends. As we are going to create a new module and as it is not depending on any other modules, just add depends as base
* data – In the data section, we have to specify all the .xml files here. In our case, we have to mention the view.xml here
So our __manifest__.py file will be like this,
{
    'name': 'Student Record',
    'summary': """This module will add a record to store student details""",
    'version': '10.0.1.0.0',
    'description': """This module will add a record to store student details""",
    'author': 'Niyas Raphy',
    'company': 'Cybrosys Techno Solutions',
    'website': 'https://www.cybrosys.com',
    'category': 'Tools',
    'depends': ['base'],
    'license': 'AGPL-3',
    'data': [
        'view.xml',
    ],
    'demo': [],
    'installable': True,
    'auto_install': False,
}
If the installable is not as set as True, the module will not have an install button when we see it in the apps list. If we set the auto_install as True, the module will automatically get installed at the time of the creation of the new database.
model.py
In this file, we have to design a new model to store the values of the student, let it be student.student. On creating a new model, a table will get generated in the database.
Inside the model, we have to declare all the fields that we are going to use in this table.
The different types of fields are,
* char
* float
* Int
* Boolean
* many2one
* many2many etc,
* selection
The model.py in our case is,
from odoo import models, fields

class StudentRecord(models.Model):

    _name = "student.student"
    name = fields.Char(string='Name', required=True)
    middle_name = fields.Char(string='Middle Name', required=True)
    last_name = fields.Char(string='Last Name', required=True)
    photo = fields.Binary(string='Photo')
    student_age = fields.Integer(string='Age')
    student_dob = fields.Date(string="Date of Birth")
    student_gender = fields.Selection([('m', 'Male'), ('f', 'Female'), ('o', 'Other')], string='Gender')
    student_blood_group = fields.Selection(
        [('A+', 'A+ve'), ('B+', 'B+ve'), ('O+', 'O+ve'), ('AB+', 'AB+ve'),
         ('A-', 'A-ve'), ('B-', 'B-ve'), ('O-', 'O-ve'), ('AB-', 'AB-ve')],
        string='Blood Group')
    nationality = fields.Many2one('res.country', string='Nationality')
First of all, we have to import the models and fields from the odoo.
(After importing the required packages give two-line space before class ).
Then we have to define a new class StudentRecord with the name as the student.student. Now a table will get generated next, we have to define the fields inside this table,(leave one line space between model name and fields) in the above we can see that the fields are a name, student_photo, student_age, etc.
Now let us look what is the type of each field,
* name – name is defined as a char field.
* middle_name – middle name is also char field
* last_name – char field
* student_photo – This a binary field where we can store the image of the student.
* student_age – Integer field to store the age of student
* student_dob – Date field to record the date of birth of the student
* student_gender – It is selection field from which the gender of the student can be selected
* student_blood_group- This is also a selection field, from this the blood group of can is selected
*student_nationality – This is a many2one field of the res.country, all the * nations list will be displayed and we can select the required one
name = fields.Char(string='Name', required=True)
Here in the name, we can see an attribute required=True, as it is given the newly created records cannot be saved/created without specifying a name for the student.
IMP:-  While giving the name for the fields, give it properly so that one can easily understand why this field is for seeing its name.
student_age = fields.Integer(string='Age')
The word that we have given the string attribute will be displayed in the form, tree views.
We can define the above fields like this also,
student_age = fields.Integer('Age')  
without string=” Age” we can directly give 'Age' inside the bracket. But giving with string is recommended.
view.xml
As we have defined all the needed fields in the model.py file now we have to create a view for this. How should the user see this, there must be the name field? Such a thing can be defined in the view.xml file.
Right now we have created a table in the database, here we have to define how it should be in the user interface and under which menu it should be, etc. In our case, let us create a new menu called the school and under the school, we can create a submenu called students and on clicking the student's menu we can display the student record.
Let us first look, how to create new menus,
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
    <data>
        <menuitem id="menu_school" name="School"/>
        <menuitem id="school_student" name="Students" parent="menu_school"  
                  action="action_view_students"/>
    </data>
</odoo>
This is how we can create new menus, In the first menu, we can see only the id and name, whereas we can see two extra attributes in the second menu, ie, action, and parent.
As the first menu does not have a parent the menu will get created a new menu in the top bar.
For the second menu, the parent is set as the first menu, you can see that in the parent of the second the id of the first menu is given. So the second menu will be the submenu of the first menu.
The string that we have given in the name attribute will be displayed as the name of the menu.
IMP: The menu that is created without having any action will not get displayed in the UI
Now let us look at what does the action in the student menu is for,
Creating the action record,
The action which takes place by clicking the menu is based on what we have defined in the action record.
Let us look at how our action record “ action_view_students” will be,
<record model="ir.actions.act_window" id="action_view_students">
            <field name="name">Students</field>
            <field name="res_model">student.student</field>
            <field name="view_type">form</field>
            <field name="view_mode">tree,form</field>
            <field name="domain">[]</field>
            <field name="help" type="html">
                <p class="oe_view_nocontent_create">Create new student
                </p>
            </field>
</record>
Here, we have to give which all views should be there, in the above I have given two views ie, tree and form view. In the res_model we have to specify the model, our model name is student.student, the name that we have given while the creation of the class in the model.py.
The domain is for, suppose if we have to filter the records by clicking the menu we can give the filter condition here.
<field name="domain">[('student_age', '>', 23 )]</field>
if we give such a domain then student those who have an age greater than 23 will be displayed.
 <p class="oe_view_nocontent_create">Create new student
  </p> 
This will get displayed if no record in the corresponding model is created. If there are no students created then it will display like this, create a new student.
Now we have to create from view and tree view for the model,
Tree view:-
<record id="view_student_tree" model="ir.ui.view">
            <field name="name">student.student.tree</field>
            <field name="model">student.student</field>
            <field name="priority" eval="8" />
            <field name="arch" type="xml">
                <tree string="Student">
                    <field name="name" />
                    <field name="middle_name" />
                    <field name="last_name" />
                    <field name="student_gender" />
                    <field name="student_age" />
                    <field name="student_dob" />
                    <field name="student_blood_group" />
                    <field name="lang" />
                </tree>
            </field>
</record>
In the id, we have to give id for tree view, in the model we have to give our model ie, student.student. The attribute tree will identify this as the tree view
Form view:-
<record id="view_student_form" model="ir.ui.view">
            <field name="name">student.student.form</field>
            <field name="model">student.student</field>
            <field name="priority" eval="8" />
            <field name="arch" type="xml">
                <form string="Student">
                    <sheet>
                        <field name="photo" widget="image" class="oe_left oe_avatar" />
                        <div class="oe_title">
                            <h1>
                                <table>
                                    <tr>
                                        <td style="padding-right:10px;"><field name="name" required="1" placeholder="First Name" /></td>
                                        <td style="padding-right:10px;"><field name="middle_name" placeholder="Middle Name" /></td>
                                        <td style="padding-right:10px;"><field name="last_name" placeholder="Last Name" /></td>
                                    </tr>
                                </table>
                            </h1>
                        </div>
                        <notebook colspan="4">
                            <page name="personal_information"
                                string="Personal Information">
                                <group col="4" colspan="4"
                                    name="personal_detail">
                                    <field name="student_gender" />
                                    <field name="student_age" />
                                    <field name="student_dob" />
                                    <field name="student_gender" />
                                    <field name="student_blood_group" />
                                    <field name="nationality" />
                                </group>
                            </page>
                        </notebook>
                    </sheet>
                </form>
            </field>
        </record>
On giving a sheet tag inside the form, a sheet will appear inside the form, it will take the form more beautiful.
IMP: If the fields are not given the group tag, the string for the field given in the model.py will not get displayed in the form view.
To display the fields on two sides of a form, we can use group tag inside group tag,
<group>
<group>
  <field name="student_age" />
</group>
<group>
<field name="student_blood_group" />
</group>
<group>
Now let us look at the whole code, that we have written
* __init__.py
	import model
* __manifest__.py
	{
    'name': 'Student Record',
    'summary': """This module will add a record to store student details""",
    'version': '10.0.1.0.0',
    'description': """This module will add a record to store student details""",
    'author': 'Niyas Raphy',
    'company': 'Cybrosys Techno Solutions',
    'website': 'https://www.cybrosys.com',
    'category': 'Tools',
    'depends': ['base'],
    'license': 'AGPL-3',
    'data': [
        'data/view.xml',
    ],
    'demo': [],
    'installable': True,
    'auto_install': False,
}
* model.py
from odoo import models, fields

class StudentRecord(models.Model):
    _name = "student.student"
    name = fields.Char(string='Name', required=True)
    middle_name = fields.Char(string='Middle Name', required=True)
    last_name = fields.Char(string='Last Name', required=True)
    photo = fields.Binary(string='Photo')
    student_age = fields.Integer(string='Age')
    student_dob = fields.Date(string="Date of Birth")
    student_gender = fields.Selection([('m', 'Male'), ('f', 'Female'), ('o', 'Other')], string='Gender')
    student_blood_group = fields.Selection(
        [('A+', 'A+ve'), ('B+', 'B+ve'), ('O+', 'O+ve'), ('AB+', 'AB+ve'),
         ('A-', 'A-ve'), ('B-', 'B-ve'), ('O-', 'O-ve'), ('AB-', 'AB-ve')],
        string='Blood Group')
*view.xml
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
    <data>
        <record id="view_student_tree" model="ir.ui.view">
            <field name="name">student.student.tree</field>
            <field name="model">student.student</field>
            <field name="priority" eval="8" />
            <field name="arch" type="xml">
                <tree string="Student">
                    <field name="name" />
                    <field name="middle_name" />
                    <field name="last_name" />
                    <field name="student_gender" />
                    <field name="student_age" />
                    <field name="student_dob" />
                    <field name="student_blood_group" />
                </tree>
            </field>
        </record>
        <record id="view_student_form" model="ir.ui.view">
            <field name="name">student.student.form</field>
            <field name="model">student.student</field>
            <field name="priority" eval="8" />
            <field name="arch" type="xml">
                <form string="Student">
                    <sheet>
                        <field name="photo" widget="image" class="oe_left oe_avatar" />
                        <div class="oe_title">
                            <h1>
                                <table>
                                    <tr>
                                        <td style="padding-right:10px;"><field name="name" required="1" placeholder="First Name" /></td>
                                        <td style="padding-right:10px;"><field name="middle_name" placeholder="Middle Name" /></td>
                                        <td style="padding-right:10px;"><field name="last_name" placeholder="Last Name" /></td>
                                    </tr>
                                </table>
                            </h1>
                        </div>
                        <notebook colspan="4">
                            <page name="personal_information"
                                string="Personal Information">
                                <group col="4" colspan="4"
                                    name="personal_detail">
                                    <field name="student_gender" />
                                    <field name="student_age" />
                                    <field name="student_dob" />
                                    <field name="student_gender" />
                                    <field name="student_blood_group" />
                                    <field name="nationality" />
                                </group>
                            </page>
                        </notebook>
                    </sheet>
                </form>
            </field>
        </record>
        <record model="ir.actions.act_window" id="action_view_students">
            <field name="name">Students</field>
            <field name="res_model">student.student</field>
            <field name="view_type">form</field>
            <field name="view_mode">tree,form</field>
            <field name="domain">[]</field>
            <field name="help" type="html">
                <p class="oe_view_nocontent_create">Create new student
                </p>
            </field>
        </record>
        <menuitem id="menu_school" name="School"/>
        <menuitem id="school_student" name="Students" parent="menu_school"
                  action="action_view_students"/>
    </data>
</odoo>
The module is now completed, make sure that the newly created module is inside the proper add-ons path. Then Go to Odoo, activate developer mode. Then Apps -> update apps list -> click on update.
The technical name of our module is the folder name (ie, the school in our case) and the name is  Student Record which is given in the manifest file.
Now after updating the apps list, you can search for the module based on either of those names.
This is now the structure of the module,
school
-- __init__.py
-- __manifest__.py
-- model.py
-- view.xml
-- static
   --- description
--icon.png
** Bold ones are folders
Extra tips
* For providing icon image for the newly created module, create a folder named static inside the school, then inside the static folder create a description folder and inside that add an image in name icon and it is format should be png.
* We can use the MVC concept in the creation of the module. So that the all .py file should be added inside the model's folder and all the .xml file should be added in the views folder.
If we are using the above concept we have to change the module structure like this,
school
-- __init__.py
-- __manifest__.py
-- models
   -- __init__.py
   -- model.py
-- views
   -- view.xml
-- static
   --- description
--icon.png
In the main __init__.py file we have to import the model's folder,
main __init__.py
       import models
In the __init__.py file inside the model's folder,
       import model
As the view.xml is moved to the views folder, the manifest file also has to be changed.
__manifest__.py
{
    'name': 'Student Record',
    'summary': """This module will add a record to store student details""",
    'version': '10.0.1.0.0',
    'description': """This module will add a record to store student details""",
    'author': 'Niyas Raphy',
    'company': 'Cybrosys Techno Solutions',
    'website': 'https://www.cybrosys.com',
    'category': 'Tools',
    'depends': ['base'],
    'license': 'AGPL-3',
    'data': [
        'views/view.xml',
    ],
    'demo': [],
    'installable': True,
    'auto_install': False,
}
This is how we can create a module in Odoo.
Odoo Blogs Odoo Development Tutorials Odoo 13 Book


If you need any assistance in odoo, we are online, please chat with us.



11
Comments

Taimur

quite helping for new beginners .

27/01/2018

-

5:18AM

Praveen

Very help beginners,Thanks

22/06/2018

-

9:54PM

Enrique

Hi, thank you for your tutorial. I followed this tutorial to create my first module, I am using odoo 13, so I had to made some modifications. The problem is that my module is not listed in the menu after successfully being installed. I have tried: restarting the server, starting in developer mode, but nothing seems to work. Any thoughts?

20/04/2020

-

3:57PM

Wendinso

Hello, I really have trouble designing the module. I did it but I can not add fields. If you can help me

18/09/2018

-

3:32AM

muhammad talha

dear thanks for given that detail but its give errors wich ask about models

18/09/2018

-

12:24AM

Niyas Raphy

Hi Thái Lao, The error says that as you have given in the manifest file, your view.xml file should be inside the folder views. If you put the file outside of that folder, change the data in manifest file view.xml or put the file inside the folder. Thanks

16/05/2018

-

2:46AM

Thái Lao

I have an error IOError: File not found: testdemo\views/view.xml can you guys help me fix this? please

16/05/2018

-

12:19AM

james

why i can't create a module

04/08/2018

-

12:58PM

Hazem

check in mainifest.py in data name of file is (view.xml) or (views.xml) i think right name is (views.xml) testdemo\views//////////view.xml <---- this file name with s (views.xml)

03/07/2018

-

5:37AM

rivan

i following your tutorial step by step, but still its doesnt working, when i acces to odoo and try to find my new module, there mesagge say that no module found, what should i do ?

02/12/2019

-

9:51PM

salah

you can install new module by this steps: 1- install your module from app store off odoo 2- Uncompressed folder 3- go to odoo and Active developer mode from setting 4- go to odoo and update apps from APP 5- search in apps for your module then install it 6- you can find your module in list of module or in setting > technical menu, based on the type of module you chose

02/05/2019

-

10:09AM



Leave a comment



whatsapp_icon
location

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635

location

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.

location

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message