This is the first in a series of posts about images and attachments in Odoo. I think it’s a topic that not all Odoo developers are completely clear on.
Each post will be a quick dive into detail about images or attachments in Odoo. Of course, we’ll focus on the latest and greatest (currently version 12.0) but there is some overlap between version.
Loading Binary Fields From A URL
Odoo stores images/Binary fields directly in the database.
So I’m talking about things like the following:
from odoo import models
class ProductTemplate(models.Model):
_inherit = "product.template"
image = fields.Binary(
string="Product Image",
attachment=False,
)
In the example above we are looking at a Binary
field called image
which is
stored on the product.template
model, not as an attachment. The default for
Binary
fields will be attachment=False
.
So if you take a look at the database table, in this case, it would be product_template
we will see a blob column for theimage
field. The contents contain a
base64 encoded binary string of the image.
Create A Image Helper Mixin
But sometimes it’s nice to work with URLs, so consider creating a mixin like the following as a helper:
import requests
import logging
import base64
_logger = logging.getLogger(__name__)
class StoresImages():
"""
Image mixin for odoo.models.Model to utilize if the data model deals with
storing Binary fields or images.
"""
def fetch_image_from_url(self, url):
"""
Gets an image from a URL and converts it to an Odoo friendly format
so that we can store it in a Binary field.
:param url: The URL to fetch.
:return: Returns a base64 encoded string.
"""
data = ""
try:
# Python 2
# data = requests.get(url.strip()).content.encode("base64").replace("\n", "")
# Python 3
data = base64.b64encode(requests.get(url.strip()).content).replace(b"\n", b"")
except Exception as e:
_logger.warn("There was a problem requesting the image from URL %s" % url)
logging.exception(e)
return data
In this mixin, we have a basic fetch_image_from_url
function which will take in a URL pointing
to an image and then return the proper string which we can store in the database.
Then Add Your Helper To Data Models
Use your mixin on your data models where you need access to functions like the fetch_image_from_url
function we created above.
class CustomModel(models.Model, StoresImages):
_name = "my.custom.model"
image_url = fields.Char(string="Image URL", required=True)
image = fields.Binary(
string="Image",
compute="_compute_image",
store=True,
attachment=False
)
@api.multi
@api.depends("image_url")
def _compute_image(self):
"""
Computes the image Binary from the image_url per database record
automatically.
"""
for record in self:
image = None
if record.image_url:
image = self.fetch_image_from_url(record.image_url)
record.update({"image": image, })
Here we created our own custom model called my.custom.model
. You can see that it uses our
StoresImages
mixin:
class CustomModel(models.Model, StoresImages)
Then we added a field for storing a single URL:
image_url = fields.Char(
string="Image URL",
required=True
)
Instead of overriding thewrite
function or updating the image with Binary strings to actually
display the image, we can create a simple compute
field that automatically converts the
image_url
field when it changes. This compute function can use our mixin/helper to make the code
clean:
image = fields.Binary(
string="Image",
compute="_compute_image",
store=True,
attachment=False
)
@api.multi
@api.depends("image_url")
def _compute_image(self):
"""
Computes the image Binary from the image_url per database
record automatically.
"""
for record in self:
image = None
if record.image_url:
image = self.fetch_image_from_url(record.image_url)
record.update({"image": image, })
Try it out by creating or updating a record:
obj = self.env["my.custom.model"].create({
"image_url": "https://..."
})
Thanks For Reading
I appreciate you taking the time to read any of my articles. I hope it has helped you out in some way. If you're looking for more ramblings, take a look at theentire catalog of articles I've written. Give me a follow on Twitter or Github to see what else I've got going on. Feel free to reach out if you want to talk!