0
votes

I have a Many2many relation inside my Odoo10 Module: Book <-> Country.

A book is available in many countries, and one country can be selected for many books.

Inside my View I choose a checkbox widget for letting the user tick the countries in which the book is available. So if the book is available in all selectable countries, there will be lots of database entries for this book.

enter image description here

So, I was wondering if there is a possibility to just save those countries in the many2many relation which are not selected - just saving the blacklist.

Any suggestions are appreciated! Thanks!

1

1 Answers

0
votes

I found a solution for my task. Here is what I did. Maybe it's helpful for someone else too.

class Book(models.Model):
  _name = 'bookstore.book'

  name = fields.Char()
  country_list = fields.Many2many('res.country', string='Available in ...', store=False, compute='_get_list', readonly=False)
  black_list = fields.Many2many('res.country', 'book_country_rel', string='BlackList', store=True)

  def _get_all_countries(self):
      return self.env['res.country'].search([])

  @api.depends('black_list')
  def _get_list(self):
      self.ensure_one()
      # 1. get all countries
      all_countries = self._get_all_countries()
      # 2. get black_list
      # 3. set all countries not in blacklist
      self.country_list = all_countries - self.black_list

  def _get_blacklist_from_country_list(self, country_list):
      self.ensure_one()
      all_countries = self._get_all_countries()

      black_list = []
      for c in all_countries:
          if c.id not in country_list:
              black_list.append(c.id)
      return black_list

  @staticmethod
  def _get_country_list(values):
    if ('country_list' in values) and values['country_list']:
      return values['country_list'][0][2]
    # else
    return []

  # set blacklist values on create and on write
  @api.model
  def create(self, vals):
      country_list = Book._get_country_list(vals)
      vals['black_list'] = [[6, False, self._get_blacklist_from_country_list(country_list)]]
      return super(blacklist_test, self).create(vals)

  @api.multi
  def write(self, vals):
      if 'country_list' in vals:
          vals['black_list'] = [[6, False, self._get_blacklist_from_country_list(vals['country_list'][0][2])]]
      return super(blacklist_test, self).write(vals)

In the view only the country list is visible:

<record model="ir.ui.view" id="book.form">
  <field name="name">Bookstore</field>
  <field name="model">bookstore.book</field>
  <field name="arch" type="xml">
    <form string="Book">
      <sheet>
          <group>
            <field name="name"/>
            <field name="country_list" widget="many2many_checkboxes"/>
          </group>
      </sheet>
    </form>
  </field>
</record>

Explanation: When selecting countries in the view (in country_list), the reference is stored temporarily. On create and on write, all countries in the database are fetched and those country ids which are not in the country_list are stored in the black_list. The compute method for country_list is important, as the value is not stored in the database (otherwise the list would be blank after saving).

Note: computed fields are not editable by default. Hence we need to set the attribute: readonly=False