Odoo图片URL模块开发手记

我们都知道,odoo中的图片支持两种存储方式,一种是将图片存储在数据库中,另外一种是存储在本地文件中。项目小时,这两种方式其实都没有什么问题,但是随着项目的扩大,一旦使用了集群,这种静态文件的增长会让问题变得棘手。于是,一直在思考有没有一种方式,可以将图片放到现在比较流行的云存储上面。之前写过一片关于AWS S3自动上传媒体文件的文章,今天我们就来实现另外一种图片模块,让用户输入URL地址,然后显示出对应的图片来。

这里主要用到了自定义字段的技术,下面就大体描述一下整个开发的过程和其中碰到的坑。

创建字段类型

我们希望能够在odoo中创建一种新的字段类型,这种字段类型在只读模式下表现为图片,当用户编辑时,变为一个输入框,当用户输入URL后,自动将URL关联的图片显示出来。

首先,我们需要创建一个新的字段类,该类是Field类的子类:

1
2
3
4
5
from odoo import fields

class ImageURL(fields.Field):
type = "imageurl"
column_type = ('varchar', 'varchar')

我们给字段类型定义为imageurl,暗示本字段在编辑模式下表现为input输入框,在只读模式下表现为图片。

创建Widget

odoo中的每种字段类型都有与之匹配的widget,我们这里主要拿Input控件来进行改造,因此widget继承自InputField:

1
2
3
4
5
var ImageURLField = InputField.extend(TranslatableFieldMixin, {
className: "o_field_image",
tagName: 'span',
supportedFieldTypes: ['char']
}

widget创建完,必须要注册到registry才能在view中加载。registry就像一个钩子,将你创建的widget与具体的前端view关联起来。

1
registry.add('imageurl', ImageURLField);

渲染图片

我们的字段的行为有连个特点,只读模式下为图片,编辑模式下为输入框。这个需要用到渲染函数_render, _render内部调用了_renderReadonly和_renderEdit方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
_renderReadonly: function () {
var url = this.value;
var $img = $(qweb.render("FieldBinaryImage-img", { widget: this, url: url }));
// override css size attributes (could have been defined in css files)
// if specified on the widget
var width = this.nodeOptions.size ? this.nodeOptions.size[0] : this.attrs.width;
var height = this.nodeOptions.size ? this.nodeOptions.size[1] : this.attrs.height;
if (width) {
$img.attr('width', width);
$img.css('max-width', width + 'px');
}
if (height) {
$img.attr('height', height);
$img.css('max-height', height + 'px');
}
this.$('> img').remove();
this.$el.prepend($img);
}

这里我们借用了BinaryImage部件的代码,因为我们想让图片在只读模式下表现的跟BinaryImage行为一致。

在没有重载_renderEdit方法时,ImageURL在只读模式下没有值,原因是其内部的值是图片,无法正确显示。因此,我们这里需要将字段的值重新赋给输入框。

1
2
3
_renderEdit: function () {
this.$el.val(this.value);
}

最终效果

你的支持我的动力