0
votes

I have a model(modelA) with one2many field related to another model(modelB) and one of the fields in modelB is a category field, which is a many2one field. The requirement is to have a one2many field displayed for each category. So if there are 2 categories named 'category1' and 'category2', the form view of modelA should have 2 one2many fields, one which displays records of having category1 and another for category2(which could possibly done using domain).

For eg modelA and modelB has the following structure.

class classA(models.Model):
    _name = 'modelA'

    modelA_one2manyfield = fields.One2many('modelB', 'modelB_many2onefield')

class classB(models.Model):
    _name = 'modelB'

    name = fields.Char()
    category = fields.Many2one('modelC')
    modelB_many2onefield = fields.Many2one('modelA')

How would i go about implementing a form view for modelA so that for each category(which can be added by the user, hence there can be of any number of categories) there is a seperate one2many field.

3

3 Answers

1
votes

What you are asking take a lot of time to give a very good answer one of the way that i think you need to try is override the fields_view_get because this is the method that retreive the view and here you can change the arch field to add a costum field take a look at this tutorial :

Tutorial for dynamic view

but i think you will have a problem, because even when you put the domain on the one2many field in XML, odoo will not filter the record when the loading happen on the view :

<!-- here all record are shown but the expected behavior is the one2many should be empty -->
<field name="one2many_field_name" readonly="1" nolabel="1" domain="[('id', '=', False)]">

but when i add this field to the python declaration

# here no record will be shown on the view and that's what was expected 
one2many_field_name = fields.One2many(..., domain=[('id', '=', False)]) 

so the question adding one2many field to arch via fields_view_get is easy but the problem is filtring data !!

1
votes

It's technically not possible. Because you can't have 2 times the same field in the same view.

But you can create a specific widget to showing what you want. How you can see in the timesheet view (My Current timesheet menu).

This is a little tutorial to created a widget. https://www.odoo.com/documentation/10.0/howtos/web.html#widgets-basics

1
votes

This not an answer but you can say a tutorial example of dynamic view : modul structur:

->dynamic_view
    --> __ini__.py
    --> models.py
    --> views.xml
    --> __manifest__.py

__manifest__.py :

# -*- coding: utf-8 -*-
        {
            'name' : 'Dynamic view',
            'version' : '1.0',
            'summary': 'Tutorial for Dynamic view',
            'sequence': 30,
            'description': """
             This Module is for showing that you can update the code of the view
             when it's called and even create new field without having to use python
             code at all
            """,
            'category': 'StackOverFlow',
            'depends' : ['base_setup',],
            'data': [
                'views.xml'
            ],
            'installable': True,
            'application': True,
            'auto_install': False,
        }

__init__.py :

        # -*- coding: utf-8 -*-
        from . import models

models.py :

# -*- coding: utf-8 -*-

        from odoo import models, fields, api


        class Person(models.Model):
            _name = "training.person"

            name = fields.Char("Full name")


        class Car(models.Model):
            _name = "training.car"
            name = fields.Char("Car name")
            mark_id = fields.Many2one(comodel_name="training.mark", string="Mark")
            owner_id = fields.Many2one(comodel_name="training.person", string="Owner")


        person_view_id = "dynamic_view.dgapr_form_person"
        # here default arch value body in the view contains only
        # name field but as we create new mark we add others field
        person_view_arch = """
                <group>
                    <field name="name"/>
                </group>
        """


        class Mark(models.Model):

            _name = "training.mark"

            name = fields.Char("Mark")

            @api.model
            def create(self, values):
                """
                   when we create a category we add one2many field to person view
                   TODO: when we unlink a category we need to remove the one2many
                         name of field is : x_mark_{id of deleted record}
                """
                rec_id = super(Mark, self).create(values)
                o2m_field = {
                    # fields created using orm method must start with x_
                   "name": "x_mark_%s"% rec_id.id,
                   "field_description": "Mark %s" % rec_id.name,
                   "ttype": "one2many",
                   "relation": "training.car",
                   "relation_field": "owner_id",
                   "stored": True,
                   "domain": "[('mark_id','=', %s)]"%rec_id.id,
                   "model_id": self.env.ref("dynamic_view.model_training_person").id,
                }
                # add on2many field to ir.model.fields
                self.env["ir.model.fields"].create(o2m_field)
                self.update_arch()
                return rec_id

            def update_arch(self):
                """
                when ever we create or delete a mark record
                we need to update the the view to add new one2many field
                if we want to hide the one2many field in view that don't have
                any record we should create compute field to use attrs features
                """
                view_id = self.env.ref(person_view_id)
                o2m_fields_ids = self.env['ir.model.fields'].search(
                    [
                        ('model_id', '=', self.env.ref("dynamic_view.model_training_person").id),
                        ('ttype', 'like', 'one2many'),
                        ('relation_field', 'like', 'owner_id')
                     ])
                o2many_arch = ""
                for o2m_id in o2m_fields_ids:
                    o2many_arch = o2many_arch + """

                        <group col="1" string="%s">
                            <field name="%s" noloable="1" />
                        </group>

                        """ % (o2m_id.field_description, o2m_id.name,)

                arch_begin = """
                     <form>
                        <sheet>
                    """
                arch_close = """
                        </sheet>
                     </form>
                     """
                arch_body = person_view_arch + o2many_arch
                new_arch = arch_begin + arch_body + arch_close

                # update the arch of the view in database
                view_id.arch = new_arch

views.xml:

<?xml version="1.0" encoding="utf-8" ?>
        <odoo>
            <data>

                <record id="dgapr_form_car" model="ir.ui.view">
                    <field name="name">car.form</field>
                    <field name="model">training.car</field>
                    <field name="arch" type="xml">
                        <form >
                            <sheet>
                                <group>
                                    <field name="name"/>
                                    <field name="mark_id"/>
                                    <field name="owner_id"/>
                                </group>
                            </sheet>
                        </form>
                    </field>
                </record>

                <record id="dgapr_action_car" model="ir.actions.act_window">
                    <field name="name">Cars</field>
                    <field name="res_model">training.car</field>
                    <field name="view_type">form</field>
                    <field name="view_mode">tree,form</field>
                </record>

                <menuitem id="menu_root_training" name="Training"/>
                <menuitem id="menu_ch_car" name="Cars" parent="menu_root_training" action="dgapr_action_car"/>


                <record id="dgapr_form_person" model="ir.ui.view">
                    <field name="name">dgapr.form.person</field>
                    <field name="model">training.person</field>
                    <field name="arch" type="xml">
                        <form>
                            <sheet>
                                <group>
                                    <field name="name"/>
                                </group>
                            </sheet>
                        </form>
                    </field>
                </record>


            </data>
        </odoo>

i found out that you can create field using ORM method even compute field. i think creating a widget is better but good to know that wen can create costum fields .

Hope this helps you

Note i didn't create a menu for person record but you can see the view by clicking on the owner_id in the car form if the new one2many field not shown just refresh the page.

Person Form after adding two category and 3 car to charif