Skip to content

Instantly share code, notes, and snippets.

@tejastank
Forked from danmana/example_model.py
Created October 19, 2023 10:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tejastank/ffe9ef28a6ec5d48edba978a41b00d8c to your computer and use it in GitHub Desktop.
Save tejastank/ffe9ef28a6ec5d48edba978a41b00d8c to your computer and use it in GitHub Desktop.
Add support for custom json fields in Odoo
from odoo import models, fields, api
from json_field import JsonField
class Person(models.Model):
_name = 'example.person'
_description = 'Person with json details'
details = JsonField() # a json object represented as dict / list / python primitives
odoo.define('custom.field_utils', function (require) {
"use strict";
var field_utils = require('web.field_utils');
var fieldRegistry = require('web.field_registry');
var basic_fields = require('web.basic_fields');
var core = require('web.core');
var _lt = core._lt;
var dom = require('web.dom');
// Extend the field_utils with json formatting and parsing,
// otherwise views will fail when trying to display the json fields
field_utils.format.json = function(value) { return JSON.stringify(value); };
field_utils.parse.json = function(value) { return JSON.parse(value); };
// Use a Textarea widget to edit json fields in the form view
var JsonTextField = basic_fields.InputField.extend({
description: _lt("Json"),
className: 'o_field_json',
supportedFieldTypes: ['json'],
tagName: 'span',
init: function () {
this._super.apply(this, arguments);
if (this.mode === 'edit') {
this.tagName = 'textarea';
}
this.autoResizeOptions = {parent: this};
},
/**
* As it it done in the start function, the autoresize is done only once.
*
* @override
*/
start: function () {
if (this.mode === 'edit') {
dom.autoresize(this.$el, this.autoResizeOptions);
}
return this._super();
},
/**
* Override to force a resize of the textarea when its value has changed
*
* @override
*/
reset: function () {
var self = this;
return Promise.resolve(this._super.apply(this, arguments)).then(function () {
if (self.mode === 'edit') {
self.$input.trigger('change');
}
});
},
/**
* @override
* @private
* @param {object} value
* @returns {boolean}
*/
_isSameValue: function (value) {
// Use deep equals (from underscore.js) for json objects to avoid infinite loops
// Because we `JSON.parse and JSON.strigify` the value in `field_utils` it will be a different instance on every check,
// so the default check with triple equals will report changes ad infinitum => infinite loop on change
return _.isEqual(value, this.value);
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Stops the enter navigation in a text area.
*
* @private
* @param {OdooEvent} ev
*/
_onKeydown: function (ev) {
if (ev.which === $.ui.keyCode.ENTER) {
ev.stopPropagation();
return;
}
this._super.apply(this, arguments);
},
});
fieldRegistry.add('json', JsonTextField);
});
from odoo.fields import Field
import psycopg2
class JsonField(Field):
"""
Represents a postgresql Json column (JSON values are mapped to the Python equivalent type of list/dict).
"""
type = 'json' # Odoo type of the field (string)
column_type = ('json', 'json') # database column type (ident, spec)
def convert_to_column(self, value, record, values=None, validate=True):
""" Convert ``value`` from the ``write`` format to the SQL format. """
# By default the psycopg2 driver does not know how to map dict/list to postgresql json types
# We need to convert it to the right db type when inserting in the db
# see https://www.psycopg.org/docs/extras.html
if value is None:
return None
else:
return psycopg2.extras.Json(value)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment