How to code a superclass field that accepts multiple subclasses? - odoo

I want to have a superclass that will be inherited by subclasses.
Let's say I want the superclass mother to be inherited by child.a and child.b.
So I make these classes
mother:
class mother(osv.osv):
_name = "mother"
mother()
child.a:
class child_a(osv.osv):
_name = "child.a"
_inherit = "mother"
child_a()
child.b:
class child_b(osv.osv):
_name = "child.b"
_inherit = "mother"
child_b()
now let's say I have a class a that have a many2one connection to mother
class a(osv.osv):
_name = "a"
_columns = {
'mother' : fields.many2one('mother', 'Mother'),
}
a()
Does mother field accept both class child.a and child.b. If yes how to code the create and write methods. If not how do I achieve this in any other way? (field accepting multiple subclasses)

No, a many2one referencing mother can't address records of class.aor class.b.
The inheritance method used for class.a and class.b actually copies the mother features. They create two new independent tables, copy of mother, containing independent data sets.
This means that the classes are not interchangeable in any way.
Records in child.a are not present in motherand vice-versa.
What you describe can be achieved with delegation inheritance - you can think that as class.x having a mother class "embedded" in it, through a special many2one relation.
This way, when you create a new class.x record, a new mother record is also implicitly created.
But this works one way: creating a new mother record does not create a class.x record.
An example of delegation inheritance in the core modules is res.users: a User "embeds" a Partner. When a new user is created, a new Partner is also created for it.
Many2one relations to Partners will also be able to reference the User embedded Partners. But many2one relations to Users will not be able to reference Partners that are not Users.

Related

How to store relational fields to the database?

I've been searching for this for a week now, and still don't find any satisfying answer. If we make any type of relationship to other model in Odoo (in any framework as well) it won't store the data inside it, it will only store its id. Now when the related model get changed, the change will also true for all the child models that's inheriting it.
I want just like in the Sale module, when I change any product in Products model, it doesn't change the same product that's already stored in the orders. Please, any help, I'm very new here to Odoo I used to develop with Java.
An order correspond to the model named sale.order which is in one2many relationship with the model sale.order.line (SOL). one SOL has it s OWN fields for price, vat... which are computed bases on the current state of product at the time of the customer order. That's why the order and its SOL are not updated when the corresponding product attributes (price...) are changed...
In Odoo : an inherited python class EXTENDS the original class (similar to java extends) : in the sale_coupon module, the model located at src/odoo/addons/sale_coupon/models/sale_order.py is :
class SaleOrder(models.Model):
_inherit = "sale.order"
extends the source class SaleOrder defined in the module sale : src/odoo/addons/sale/models/sale.py:
class SaleOrder(models.Model):
name = "sale.order"
That's mean that the inherited class SaleOrder (_inherit) gets the specific attributes (fields) and methods (def) provided and defined in its source(s) class(es) : saleOrder :
origin = fields.Char(string='Source Document', help="Reference of the document that generated this sales order request.")
def _amount_all(self):
""" Compute the total amounts of the SO."""
for order in self:
amount_untaxed = amount_tax = 0.0
for line in order.order_line:
amount_untaxed += line.price_subtotal
amount_tax += line.price_tax
...
And you can add new fields and new methods in your inherited class SaleOrder scope :
reward_amount = fields.Float(compute='_compute_reward_total')
def action_confirm(self):
self.generated_coupon_ids.write({'state': 'new'})
...
return super(SaleOrder, self).action_confirm()
But, you don t need to instantiate theses Classes in your code (you don t need to create yourself Objects).
Theses classes have the basic CRUD-methods provided from models.Model: def create(), def read(), def write(), def unlink()
The source and the inherited class(es) both are connected to the same database-table : sale_order
So one Class-record (python in Odoo) :
self.env['sale.order'].browse(12)
corresponds to one record in the database-table : sale_order
Theses classes (SaleOrder) have the CRUD-methods from model.Model : def create(), def read(), def write(), def unlink() and they can override them in their own scope, where you can optionally call the "parent"-def : super(SaleOrder, self).unlink() :
def unlink(self):
for order in self:
if order.state not in ('draft', 'cancel'):
raise UserError(_('You can not delete a sent quotation or a confirmed sales order. You must first cancel it.'))
return super(SaleOrder, self).unlink()
Relations betweens models are defined using fields :
A relation between the sale.order model and the res.partner model (contact) is created using fields.Many2one:
class SaleOrder(models.Model):
...
partner_id = fields.Many2one('res.partner')
which is reflected in the corresponding database-table.
First of all, If you change the product details It will these details will change accordingly in the sale order after you refresh, about store the id of relation field its the standard way to use,
but there Is another way I think this is the way you looking for which Is store data as a JSON in column with type JSON as an example for sale order line table if you want to store the product as a JSON column it will be like below:
[{"id": 1, "name": "product 1"},]
of course, there Is a way to read and update and create the data into a JSON column you can read about It.
one more way as an example if you want to store the product to the current record of relation table not just store the Id and query to get the result you can just create new fields for data you want to store like if you want to store the name and price with name and id then you must add fields for this date and when you create in order line rather than add just product Id as a relation just add the product data to the new fields you have added before but this is not a good way.
I hope I understand your question and this answer helps you.

Change column name for non-primitive field (navigation) with EF Core

Given the following classes:
public class Mission
{
private MissionCard _missionCard;
}
public class MissionCard
{
}
I would like to create this relationship via Fluent API so that _missionCard is treated as a relationship and can be populated from DB but isn't available as a property on my Mission model.
I can create that relationship with:
modelBuilder.Entity<Mission>().HasOne<MissionCard>("_missionCard");
but by default this creates a FK column named "_missionCard". The docs show that a custom name can be specified when using .Property("property name").FromField("field name") but you cannot use .Property for non-primitive types.
Is it possible to change the column name for a relationship like above?
Managed to resolve this by inverting the relationship:
modelBuilder.Entity<MissionCard>()
.HasMany<Mission>()
.WithOne("_missionCard")
.HasForeignKey(nameof(MissionCard));

Use of _inherit and _name for the same model will only create table or will also copy its methods(Functions)?

I read an answer about this scenario, the link is bellow
https://www.odoo.com/forum/help-1/question/the-different-openerp-model-inheritance-mechanisms-what-s-the-difference-between-them-and-when-should-they-be-used-46​
Specifically to my question the above answer explains
If your class _inherit one model and you set a _name different it will create a new model in a new database table.
So my question is, this approach will create(inherit) the methods of inherited model as well or I have to define all the methods again?
All the methods and fields will be copied to new model when you will use _inherit and _name both.

cannot add fields to a many2many relation class

I created a site class having many2many relation with text class. I'm trying to add some attributes to the many2many relation class.
This is the site class:
class site(models.Model):
_name ='ab.site'
name = fields.Char('Name')
text_ids = fields.Many2many('ab.site.text',
'ab_site_text_rel',
'text_id',
'site_id',
'Texts')
This is the text class:
class text(models.Model):
_name = 'ab.text'
name = fields.Char('Title', required=True)
I need to create a non-conformity depending at the same time on the text class and the site class, the user can add a list of non-conformities in the site depending on legal texts, so the non-conformity class is related to both, that's why I'm trying to add it to the relation class.
I create the relation class, I added the applicability field (boolean) and a one2many field (non-conformities):
class ab_site_text_rel(models.Model):
_name = "ab.site.text.rel"
_rec_name = "site_id"
site_id = fields.Many2one('ab.site', 'Site', ondelete='cascade')
text_id = fields.Many2one('ab.site.text', 'Text', ondelete='cascade')
applicability = fields.Boolean(string='Applicability')
nonconformity_ids = fields.One2many('ab.nonconformity','ab_site_text_rel','Non-conformities')
I got this key error when running the server:
File "/home/euromed/git/odoo9/openerp/modules/registry.py", line 200, in setup_models
model._setup_fields(cr, SUPERUSER_ID, partial)
File "/home/euromed/git/odoo9/openerp/api.py", line 250, in wrapper
return old_api(self, *args, **kwargs)
File "/home/euromed/git/odoo9/openerp/api.py", line 354, in old_api
result = method(recs, *args, **kwargs)
File "/home/euromed/git/odoo9/openerp/models.py", line 3046, in _setup_fields
field.setup_full(self)
File "/home/euromed/git/odoo9/openerp/fields.py", line 495, in setup_full
self._setup_regular_full(model)
File "/home/euromed/git/odoo9/openerp/fields.py", line 1893, in _setup_regular_full
invf = comodel._fields[self.inverse_name]
KeyError: 'ab_site_text_rel'
Relational Fields:
Relational fields are fields with values that refer to other objects. Relationship can be Unidirectoinal or Bi-directional.
In general, there are main three types of relation.
1. Many2one
Normal relationship towards to other objects (using a foreign key)
Invoice lines contains reference of invoice (invoice_id)
invoice_id = fields.Many2one(comodel_name='account.invoice', string='Invoice')
2. One2many
Virtual relationship towards multiple objects (inverse of many2one).
A one2many relational field provides a kind of “container” relation:
the records on the other side of the Relation can be seen as
“contained” in the record on this side.
In a one-to-many relationship between Table A and Table B the rows in
Table A are linked to zero, one, or many rows in Table B. This
relationship allows information to be saved in a table and referenced
many times in other tables.
invoice_line = fields.One2many(comodel_name='account.invoice.line', inverse_name='invoice_id', string='Invoice Line')
3. Many2many
Bi-directional multiple relationship between objects.
This is the most general kind of relation: a record may be related to any number of records on the other side, and vice-versa.
In the case of a many-to-many relationship, each row in Products is linked to zero, one or many rows in Taxes and vice versa. Normally, New Table a mapping table is required to map such kind of relationships.
In this relationship new table is required to store reference of the
both table.
Many2many field definition.
taxes_id = fields.Many2many(comodel_name='account.tax', relation='product_taxes_rel', column1='prod_id', column2='tax_id', string='Customer Taxes')
========================================================================
Actually in this framework we don't need to care about the relational table of M2M, that will be auto managed. So in your case it's not required. And I am not sure why you have created this class, be specific with your requirements. And try to update question with the target you want to achieve.
class ab_site_text_rel(models.Model):
This is not required.

django query multiple tables with foreign key pointing on self

lets say I have a model named User, and other models representing actions done by the a user, like "User_clicked", "User_left", "User_ate_cookie" etc. etc.
the User_* models have different fields and inherit from a single abstract class (User_do_something)
my question is this:
what's the django-way of querying ALL the models, from all the relevant tables, that point on a specific user?
eg. I want to do User.get_all_actions() and get a list with mixed type of models in them, containing all the objects that inherit from User_do_something and point on the specific user.
Note: performance is critical. I don't want to make multiple db queries and combine the list, if possible, I want to do it with a single sql select.
some code to be clear:
class User(models.Model):
uuid = models.UUIDField(unique=True, default=uuid.uuid4)
creation_time = models.DateTimeField(auto_now_add=True)
def get_all_actions(self):
'''
return a list with ALL the actions this player did.
'''
??????? how do I do this query ???????
class User_do_action(models.Model):
user = models.ForeignKey(User)
creation_time = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
class User_click(User_do_action):
... some fields
class User_left(User_do_action):
... some fields
class User_ate_cookie(User_do_action):
... some fields
etc. etc.
thanks!