0
votes

I've been asked to develop a tag system for attachments in Odoo.

While for attachments I've found this standard module (called Document Management System), I didn't find anything useful for tag management.

Thus, I've developed my own, custom module in which attachments (represented by the core ir.attachment model) have been extended with a Many2many relation with a tag model, that in turn represents... a tag, and has a tag field representing the actual tag's textual content.

Then I've been struggling with search by tag...

Odoo search views are based on A OP B expressions where A is a model's field, OP is an operator (e.g. =) and B (usually) is the searched term (but it can be any Python expression).

The problem here is that the searched term has to be compared with a related object's fields (i.e. the tags), not with a field of the attachment itself.

So I came up with a workaround. I've extended the attachment model with:

  • a computed char field called tags with an associated custom search method _search_tags
  • a boolean field called found_by_tag

_search_tags is invoked each time a search is performed and its job is to set the flag found_by_tag to the proper value, based on the searched term.

Thus, the expression for the search view becomes [('found_by_tag', '=', True)].

That's the relevant part from the Python code:

# Attachments
class attachment(models.Model):
 _inherit = 'ir.attachment'

 # Tag management
 tag_ids = fields.Many2many('attachmentssample.tag', string = 'Tags')
 tags = fields.Text(compute = '_compute_tags', search = '_search_tags')
 found_by_tag = fields.Boolean()

 @api.one
 @api.depends('tag_ids')
 def _compute_tags(self):
  tags = ''
  for tag in self.tag_ids:
   tags += tag.tag + ','
  self.tags = tags

 def _search_tags(self, operator, value):
  attachments = self.search([])
  for attachment in attachments:
   attachment.checkIfRelevantFor(value)
  return [('found_by_tag', '=', True)]

 def checkIfRelevantFor(self, search_tag):
  relevant = False
  for tag in self.tag_ids:
   if tag.tag == search_tag:
    relevant = True
  if relevant:
   self.found_by_tag = True
  else:
   self.found_by_tag = False

# Tags
class tag(models.Model):
 _name = 'attachmentssample.tag'

 tag = fields.Char()

While the workaround actually works, I'm wondering if that's too much. Is there a simpler way to implement a search by tag? Or, alternatively, is there a module that may be used for this purpose?

2

2 Answers

0
votes

Not sure this module exist on community,

But ideally looking from odoo implementation guidelines, what you havw done is perfectly correct. You wanna use extra model for tags if you think you want to advance css styling and reusablity factors. You will see this things in v9 already done

On second thought, if you think those tags are just informative then you can just make text field and store comma-seperated vales and your helper method can easily split or join by comma. Why this idea. Cause this will greatly reduce db IO for tags evrytime you read attachment and fact that ir.attachment is linked to all model records, over all idea eliminating table would be great for performance as python code be way faster then db IO.

Bests

0
votes

I came up with the best possibile solution. In the book Odoo Development Essentials it is explained that the 'in' operator in domain expressions behaves differently when the left-hand side is a "to-many" field. In that case the semantics of ('A', 'in', B) becomes "keep the record with id B if B is one of the ids of the records referenced by A". In other words, the expression should be read in reverse. With this knowledge, you can implement search by tag in 2 steps:

  1. Find a tag matching the current query.
  2. Use its id inside a domain expression like ('attachment_ids', 'in', id).

With this strategy you don't need additional fields just to support search.

(Man... Odoo development is... challenging)