<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: All Next Ver</title>
    <description>The latest articles on DEV Community by All Next Ver (@all_next_ver).</description>
    <link>https://dev.to/all_next_ver</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4195829%2F01afcc89-a155-4173-a831-c55afb1411a5.png</url>
      <title>DEV Community: All Next Ver</title>
      <link>https://dev.to/all_next_ver</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/all_next_ver"/>
    <language>en</language>
    <item>
      <title>How to Add Custom Fields to Odoo Contacts with a Small Custom Module</title>
      <dc:creator>All Next Ver</dc:creator>
      <pubDate>Tue, 20 Oct 2026 09:40:15 +0000</pubDate>
      <link>https://dev.to/all_next_ver/how-to-add-custom-fields-to-odoo-contacts-with-a-small-custom-module-2la4</link>
      <guid>https://dev.to/all_next_ver/how-to-add-custom-fields-to-odoo-contacts-with-a-small-custom-module-2la4</guid>
      <description>&lt;p&gt;Almost every Odoo project ends up needing one extra field on the contact form: a customer segment, a preferred contact time, an internal reference. The clean way to add it is a small custom module that extends &lt;code&gt;res.partner&lt;/code&gt;, not editing core files or using Studio exports.&lt;/p&gt;

&lt;p&gt;In this post we build a module called &lt;code&gt;partner_extra_fields&lt;/code&gt; that adds two fields to the contact form. It takes about ten minutes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I wrote this for Odoo &lt;strong&gt;[VERSION YOU TESTED]&lt;/strong&gt;. Field and view names below are standard, but check the notes at the end if you use a different version.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What we are building
&lt;/h2&gt;

&lt;p&gt;A module that adds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Customer Segment&lt;/code&gt; (a dropdown: Retail, Wholesale, Corporate)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Preferred Contact Time&lt;/code&gt; (free text)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both appear on the contact form, right after the Tax ID field.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create the module structure
&lt;/h2&gt;

&lt;p&gt;Inside your custom addons folder, create this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;partner_extra_fields/
├── __init__.py
├── __manifest__.py
├── models/
│   ├── __init__.py
│   └── res_partner.py
└── views/
    └── res_partner_views.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: The manifest
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;__manifest__.py&lt;/code&gt; tells Odoo what your module is and which files to load.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Partner Extra Fields&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.0.0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Adds customer segment and preferred contact time to contacts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Contacts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;depends&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;views/res_partner_views.xml&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;license&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LGPL-3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;installable&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Extend the model
&lt;/h2&gt;

&lt;p&gt;Odoo lets you extend an existing model with &lt;code&gt;_inherit&lt;/code&gt;. We do not create a new table; we add columns to &lt;code&gt;res.partner&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;models/__init__.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;res_partner&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;models/res_partner.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;odoo&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ResPartner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_inherit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;res.partner&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

    &lt;span class="n"&gt;customer_segment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Selection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;retail&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Retail&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wholesale&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Wholesale&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;corporate&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Corporate&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Customer Segment&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;preferred_contact_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Preferred Contact Time&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the root &lt;code&gt;__init__.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Show the fields in the form
&lt;/h2&gt;

&lt;p&gt;Fields in the database are not visible until a view shows them. We inherit the standard partner form and place our fields after &lt;code&gt;vat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;views/res_partner_views.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;odoo&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;record&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"view_partner_form_inherit_extra_fields"&lt;/span&gt; &lt;span class="na"&gt;model=&lt;/span&gt;&lt;span class="s"&gt;"ir.ui.view"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;res.partner.form.inherit.extra.fields&lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"model"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;res.partner&lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"inherit_id"&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"base.view_partner_form"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"arch"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"xml"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"vat"&lt;/span&gt; &lt;span class="na"&gt;position=&lt;/span&gt;&lt;span class="s"&gt;"after"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"customer_segment"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"preferred_contact_time"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/record&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/odoo&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Install it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add your custom addons folder to &lt;code&gt;addons_path&lt;/code&gt; in &lt;code&gt;odoo.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Restart the Odoo service.&lt;/li&gt;
&lt;li&gt;Turn on developer mode, go to &lt;strong&gt;Apps&lt;/strong&gt;, click &lt;strong&gt;Update Apps List&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Search for "Partner Extra Fields" and click &lt;strong&gt;Install&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Open any contact. Your two fields should appear under Tax ID.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you change the code later
&lt;/h2&gt;

&lt;p&gt;Odoo does not reload Python or XML changes automatically. Restart the service and upgrade the module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./odoo-bin &lt;span class="nt"&gt;-c&lt;/span&gt; odoo.conf &lt;span class="nt"&gt;-d&lt;/span&gt; your_database &lt;span class="nt"&gt;-u&lt;/span&gt; partner_extra_fields
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting an &lt;code&gt;__init__.py&lt;/code&gt;.&lt;/strong&gt; If a folder has no &lt;code&gt;__init__.py&lt;/code&gt;, Odoo ignores it silently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skipping the &lt;code&gt;-u&lt;/code&gt; upgrade&lt;/strong&gt; after changing a view, then wondering why nothing changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A wrong &lt;code&gt;inherit_id&lt;/code&gt;.&lt;/strong&gt; A typo in &lt;code&gt;base.view_partner_form&lt;/code&gt; throws an error on install.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A missing anchor field.&lt;/strong&gt; If the field you inherit after (&lt;code&gt;vat&lt;/code&gt;) is not in your view, use an &lt;code&gt;xpath&lt;/code&gt; against a field that is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version differences.&lt;/strong&gt; Between Odoo versions, view tags and some attributes change (for example, list views were renamed from &lt;code&gt;tree&lt;/code&gt; to &lt;code&gt;list&lt;/code&gt; in newer versions). Always read the release notes for your version.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;That is the whole pattern: a model extension for the data, a view inheritance for the screen, and a manifest to tie them together. Once you are comfortable with it, you can add constraints, computed fields, security rules and reports the same way.&lt;/p&gt;

&lt;p&gt;If you have a specific field you want to add, or an Odoo error you are stuck on, leave a comment and I will help where I can.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I work at &lt;a href="https://allnextver.com" rel="noopener noreferrer"&gt;All Next Ver&lt;/a&gt;, a software company in Dhaka building Odoo and custom ERP solutions.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>softwaredevelopment</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
