Articles > Odoo images and attachments — Load from URL

Odoo images and attachments — Load from URL

Written by
Holden Rehg
Posted on
February 4, 2019

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!

web development
odoo
software
open source
python
Share:

Holden Rehg, Author

Posted February 4, 2019