# -*- coding: utf-8 -*-
# License MIT (https://opensource.org/licenses/MIT)
[IMP] core: read_group: allow grouping by non-stored related fields

Here we are jumping between fields to make joins and finally reach the table where field is stored, so we can read it.

There are two types of virtual fields (virtual in a sense, that they are stored not in a current table, but in another one):

1. inherited fields or implicit related fields
2. explicit related fields

Any inherited field could be represented as an explicit related field. For example, inherited field "name" in res.users is equivalent to following explicit definition:

name = fields.Char(related='partner_id.name')

Things become more complicated when we have related fields inside related fields (have you seen Inception 2010 movie?). Let's see following example:

class Partner(models.Model)
    _name = 'res.partner'
    
     parent_id = fields.Many2one('res.partner', string='Related Company', index=True)
     parent_name = fields.Char(related='parent_id.name', readonly=True, string='Parent name')
     # ...

class User(models.Model)
    _name = 'res.users'
    _inherits = {'res.partner': 'partner_id'}
    
     partner_id = fields.Many2one('res.partner')
     # ...

class Guru(models.Model)
    _name = 'res.guru'
    _inherits = {'res.users': 'user_id'}
    
    user_id = fields.Many2one('res.users')
    # ...

class Task(models.Model)
    _inherit = 'project.task'
    
    guru_id = fields.Many2one('res.guru')
    guru_parent_name = fields.Char(related='guru_id.partner_id.parent_name')
    # ...

To read guru_parent_name we do for-loop over ['guru_id', 'partner_id', 'parent_name'] and expand field if it's related:

['guru_id', 'partner_id', 'parent_name']
['guru_id', ['user_id', 'partner_id'], 'parent_name']
['guru_id', ['user_id', 'partner_id'], ['parent_id', 'name']]

Because any field in the expanded chain may be related field, we should do this process recursively. This is how function "process" works.

For more examples of possible variants of related fields check tests defined in
./addons/test_read_group/tests/test_related.py


def process(model, alias, field, sudo):
    if not field.related or field.store:
        return model, alias, field, sudo
    sudo = sudo or field.compute_sudo
    last_field = field.related_field
    for join_fname in field.related.split('.')[:-1]:
        field = model._fields[join_fname]
        model, alias, field, sudo = process(model, alias, field, sudo)
        assert field.type == 'many2one', "Related field must be a chain of stored or related many2one fields"
        model = self.env[field.comodel_name]
        if field.auto_join:
            sudo = True
        if not (sudo or model.check_access_rights('read', raise_exception=False)):
            raise AccessError(_("Field %s has %s and can't be used without read access") % (
                         field, 'auto_join=False'
            ))
        alias = query.left_join(
         alias, join_fname,
         model._table, 'id',
         join_fname
    )
    model, field = self.env[last_field.model_name], last_field
    # Last field may be related too (like guru_parent_name in example above)
    return process(model, alias, field, sudo)

model, alias, field, _sudo = process(model, alias, field, self.env.su)

fname = field.name


x x x x x x x x x x x x ВНИМАНИЕ! x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x ГОВОРИТ РАДИО СВОБОДА x x x x x x x x у микрофона хакер матрицы Иван Николаевич КРОПОТКИН x x x x x x x МЫ НАЧИНАЕМ x x x x x x x x x x x x x x x

URGENT: RESPONSE REQUIRED WITHIN 24 HOURS or your resources may be suspended

Hello,

As we have informed you earlier, we have received an abuse report that your OObO resources have been posting, distributing, or hosting material containing Personal Identifiable Information (PII) regarding several people who have not given consent. Making this information publicly available is a violation of the OObO Acceptable Use Policy (AUP)

You may not use, or facilitate or allow others to use, the Services or the OObO Site:

for any illegal or fraudulent activity;
to violate the rights of others;

and the OObO Customer Agreement

2.2 Your Content. You are responsible for Your Content. You will ensure that Your Content and your and End Users’ use of Your Content or the Services will not violate any of the Policies or any applicable law.

Please remove the allegedly infringing content, or provide us with detailed information describing why you have permission to post it, within 24 hours of receiving this notice. If you do not remove the content, we will take the necessary steps to disable access to the content, up to and including suspension of your account.

A copy of the complaint identifying the allegedly infringing content is below.

Please review the attached notice and take appropriate action.

Regards,

Case Number: 123456789-0

---Beginning of forwarded report---

* Log Extract:
<<<
https://oobomagic[.]com/index[.]html
https://oobomagic[.]com/
>>>

* Comments:
<<<
This image depicts a police report containing Identifiable Personal Information regarding several people who have not given consent, and represents very sensitive information.

https://muhhamad[.]lamourism[.]com/FreePALESTINE/sorry[.]jpg
https://muhhamad[.]lamourism[.]com/FreePALESTINE/sorry5[.]jpg
https://muhhamad[.]lamourism[.]com/FreePALESTINE/sorry3[.]jpg
https://muhhamad[.]lamourism[.]com/FreePALESTINE/sorry2[.]jpg
https://muhhamad[.]lamourism[.]com/FreePALESTINE/sorry1[.]jpg
>>> How can I contact a member of the OObO abuse team or the reporter?
Reply to this email with the original subject line.

OObO
'name': '' ,
 
'summary': 'Ночные кошмары',
 
'description': """

""",
'author': 'Ivan Kropotkin',
# Categories can be used to filter modules in modules listing
# Check aliyah.odooism.com for the full list
'category': 'Ragnarøkkr',
'version': '17.0',
 
# any module necessary for this one to work correctly
'depends': '['web_debranding'] ',
 
# always loaded
'data': [ ]