restrict, no action & set default in ondelete optional parameter for fields - odoo

I am learning about optional parameter regarding fields for ondelete parameter.
These are the predefined values: "cascade", "set null", "restrict", "no action", "set default"
Can anyone explain in detail about the
difference between RESTRICT and NO ACTION.
how SET DEFAULT is used in OpenERP 7?
where to set default value for the field ?
how to define set default value in python code itself?

Take for example a Course with Students. On Students is a foreign key to Course. The ondelete determines what happens with the student_id column (on Course) when the Student is deleted.
CASCADE: Delete the Course record with matching student_id when Student is deleted
RESTRICT: Cannot delete the Student as long as it is related to a Course.
NO ACTION: similar, but is a deferred check: You can delete the Student but you have to make sure that the integrity is OK when the transaction is committed.
SET DEFAULT: uses openerp default definition (see _defaults dict in the python model definition)
SET NULL: when a Student gets deleted, the student_id becomes NULL in the DB.
In Python you can find these in _columns defintion:
_columns = {
'student_id': fields.many2one(
'my.student',
'Student',
ondelete='set null',
),

Related

duplicate key value violates unique constraint Error using sql_constraints

I have used as
_sql_constraints = [
('bpv_uniq', 'unique (branch_id,product_id,product_tmpl_id)', "There are Other Reference Purchase Price in same branch, please change branch"),
]
I have removed this code and upgrade module. But on data entry still gives the following error;
duplicate key value violates unique constraint "reference_price_uniq"
DETAIL: Key (branch_id,product_id,product_tmpl_id)=(2,31,27) already exists.
Please guide.
One way is to override the constraint to check nothing instead.
_sql_constraints = [('bpv_uniq', 'CHECK(1==1)', "There are Other Reference Purchase Price in same branch, please change branch"),]

Odoo 12: Many2one ondelete message?

Is it possible to change(edit) default ondelete message in Many2one field?
My field is:
parent_id = fields.Many2one("pgp.organizational.classifications", string="Parent classification", select=True, ondelete='restrict')
Default message is like this, but I won't to add my message:
"Odoo Server Error - Greška kod provjere
The operation cannot be completed, probably due to the following:
- deletion: you may be trying to delete a record while other records still reference it
- creation/update: a mandatory field is not correctly set
[objekt s referencom: pgp.organizational.classifications - pgp.organizational.classifications] "
You cannot change it in the Many2one field's declaration.
Code which generates this message is there: https://github.com/odoo/odoo/blob/12.0/odoo/service/model.py#L120-L154
Seems to be tricky to overload
Restricting and cascading deletes are the two most common options. RESTRICT prevents deletion of a referenced row. NO ACTION means that if any referencing rows still exist when the constraint is checked, an error is raised; this is the default behavior if you do not specify anything. (The essential difference between these two choices is that NO ACTION allows the check to be deferred until later in the transaction, whereas RESTRICT does not.) CASCADE specifies that when a referenced row is deleted, row(s) referencing it should be automatically deleted as well. There are two other options: SET NULL and SET DEFAULT. These cause the referencing columns to be set to nulls or default values, respectively, when the referenced row is deleted. Note that these do not excuse you from observing any constraints. For example, if an action specifies SET DEFAULT but the default value would not satisfy the foreign key, the operation will fail.
I solved it by overloading unlink method.
Here is the code if it helps someone:
> #api.multi
> def unlink(self):
> for field in self:
> if field.parent_id:
> raise UserError(_('It is not possible to delete a record that is already used in transactions!'))
> return super(YourClass, self).unlink()

How to create a relation fields in odoo?

There are no proper examples on how to create relational fields in openerp like one2many, many2many, many2one and one2one. So can anyone show me with example on sales module.
Might helps you,
_columns = {
'current_rate': fields.related('company_currency_id','rate_silent', type='float', relation='res.currency',digits_compute=dp.get_precision( 'Account'), string='Current Rate', readonly=True),
}
Here,
company_currency_id => the field in the same model through which the new field will be relate,
rate_silent => is the field which you are going to relate with new field, means the field from source model,
relation => is the source model name,
type => is the datatype of the source field
Note : When you update value in your newly defined related field it
will be updated in source field as well, though it's always advisable
to set readonly in newly defined field.
I don't have particular example of sales module. But you can get the general idea from below syntax.It would be helpful for any kind of application.
class openerp.fields.Many2one(comodel_name=None, string=None, **kwargs)
Bases: openerp.fields._Relational
The value of such a field is a recordset of size 0 (no record) or 1 (a single record).
Parameters
comodel_name -- name of the target model (string)
domain -- an optional domain to set on candidate values on the client side (domain or string)
context -- an optional context to use on the client side when handling that field (dictionary)
ondelete -- what to do when the referred record is deleted; possible values are: 'set null', 'restrict', 'cascade'
auto_join -- whether JOINs are generated upon search through that field (boolean, by default False)
delegate -- set it to True to make fields of the target model accessible from the current model (corresponds to _inherits)
The attribute comodel_name is mandatory except in the case of related fields or field extensions.
=======================================================================
class openerp.fields.One2many(comodel_name=None, inverse_name=None, string=None, **kwargs)
Bases: openerp.fields._RelationalMulti
One2many field; the value of such a field is the recordset of all the records in comodel_name such that the field inverse_name is equal to the current record.
Parameters
comodel_name -- name of the target model (string)
inverse_name -- name of the inverse Many2one field in comodel_name (string)
domain -- an optional domain to set on candidate values on the client side (domain or string)
context -- an optional context to use on the client side when handling that field (dictionary)
auto_join -- whether JOINs are generated upon search through that field (boolean, by default False)
limit -- optional limit to use upon read (integer)
The attributes comodel_name and inverse_name are mandatory except in the case of related fields or field extensions.
==========================================================================
class openerp.fields.Many2many(comodel_name=None, relation=None, column1=None, column2=None, string=None, **kwargs)
Bases: openerp.fields._RelationalMulti
Many2many field; the value of such a field is the recordset.
Parameters----------------------------------------------------------------
comodel_name -- name of the target model (string)
The attribute comodel_name is mandatory except in the case of related fields or field extensions.
Parameters
relation -- optional name of the table that stores the relation in the database (string)
column1 -- optional name of the column referring to "these" records in the table relation (string)
column2 -- optional name of the column referring to "those" records in the table relation (string)
The attributes relation, column1 and column2 are optional. If not given, names are automatically generated from model names, provided model_name and comodel_name are different!
Parameters
domain -- an optional domain to set on candidate values on the client side (domain or string)
context -- an optional context to use on the client side when handling that field (dictionary)
limit -- optional limit to use upon read (integer)

Remove SQL constraint in OpenERP7

In OpenERP7, the core module account has a declaration for account.invoice which has, at some point, the following declaration:
addons/account/account_invoice.py:343
_sql_constraints = [
('number_uniq', 'unique(number, company_id, journal_id, type)', 'Invoice Number must be unique per Company!'),
]
In a module which redefined account.invoice I wanted to remove the constraint with two different approaches:
Removing it in init (account_invoice::init(self, pool, cr))
def __init__(self, pool, cr):
super(account_invoice, self).__init__(pool, cr)
try:
cr.execute('ALTER TABLE account_invoice DROP CONSTRAINT IF EXISTS account_invoice_number_uniq')
finally:
pass
Replacing the constraint
_sql_constraints = [
('number_uniq', 'check(1=1)', 'Dummy check, always true, used to replace the previous constraint'),
]
However, when I reinstall the module in which those two declarations were made, I get an error (in the PG logs) telling me that the constraint account_invoice_number_uniq could not be craeted for a unique key since there's repeated data.
How can I prevent having such error? How can I prevent the system attempting to create (first; then... replace/delete) the constraint?
Check the Below Reference Link to remove the SQL Constraint Of Parent Class in Odoo
Click To See the Reference For Remove the SQL Constraint In Odoo(formally OpenERP)

Nhibernate foreign key constraint due to unexpected update of already inserted record

This is a strange one replicated in the following code:
using (ISession session = RepositoryTestHelper.SessionFactory.OpenSession())
{
//session.BeginTransaction();
UserRepo repo = new UserRepo(session);
CompanyRepo cRepo = new CompanyRepo(session);
var user = repo.FindByEmail("test.user#blah.com");
user.CompanyAssociations.Add(new CompanyUserAssoc()
{
User = user,
Company = cRepo.GetById(1)
});
repo.AddOrUpdate(user);
//session.Transaction.Commit();
}
And the relationship between user, company and CompanyUserAssoc is fairly straight forward:
For the company:
HasMany<CompanyUserAssoc>(x => x.UserAssociations).KeyColumn("User_id");
For the user:
HasMany<CompanyUserAssoc>(x => x.CompanyAssociations).KeyColumn("Company_id")
And for the association class itself:
References(x => x.Company).UniqueKey("CompanyId_UserId");
References(x => x.User).UniqueKey("CompanyId_UserId");
Now this is where I am baffled. Notice in my initial code that the begin and commit trans calls are commented out. This actually means the code will work! The CompanyUserAssoc is created and correctly references the user and the company with id of 1. Great!
But... sadly when I put this in a transaction i get this error:
{"The UPDATE statement conflicted with the FOREIGN KEY constraint \"FK3C47859753A62C6E\". The conflict occurred in database \"xxxx\", table \"dbo.Company\", column 'Id'.\r\nThe statement has been terminated."}
But why? Well that's my question. What i have see in the profiler is that it does this:
exec sp_executesql N'UPDATE [CompanyUserAssoc] SET Company_id = null WHERE Company_id = #p0',N'#p0 int',#p0=1
Wait... what? NULL? Why is it setting the company id to null? and why is it only doing this when in a transaction? What's "wrong" with my Nhibernate mapping?
Since both collections are mapped as non-inverse (the default) and the Company collection has no users, it will issue that update to clear the link table. Could you try setting the UserAssociations to inverse? Or, what I usually do when an explicit link table is involved, is set both HasManys to inverse and simply work with the link table directly.
This was a red herring in the end, a fish I have come to despise. I had not noticed in my haste and dependence on intellisense that the UserAssocations property of the Company was not an IList but an IList! yes I have stupidly chosen the Nhib map class instead of the domain class.. This weirdly didn't error in the way you would expect, and worked without a transaction, but why?
Well - Nhib was able to insert the assoc entry, but then believed it needed to update that same table with the id it had already inserted (because it somehow sees it as a different entity?). I would have expected a compilation error here in the map class itself as I was using the type, but no. And without a transaction the sql generated works.
I would investigate more as to why, but I've answered this just to highlight a rare and silly mistake which can lead to a lot of investigation if missed.