Update One2many Fields in the view - python-2.7

I have a model A which has an one2mny relation with another model B and the later has also an one2many relation with a model C.
I want to use self.update to update the one2many relation in the model A in and onchange method so accordingly update the one2many relation in the model B.
I have managed to update the first one but the second one is not updated here what i have done :
temp.append((0,0,{
'periode':periode,
'ca':ca,
'loc':loc,
'line_rs':line_rsc,
}))
self.update({
'periode_line':temp
})
where line_rsc is a list that should be used to update the second
one2many relation
Thanks

secod pic (secod one2many relation):

i tried this using the new api and it seems to be working just fine:
# this will add the new record to existing records
#api.onchange(..)
def .....(self):
self.update(
{'o2m_1_field': [{
'o2m_1_field_name': 'value',
'o2m_1_field_o2m_2_name': [{'o2m_2_field': 'value'}]
}]
}
)
this logic works fine in new api.
or you can do it like this
# this will add the new record to existing records
self.o2m_1_field += self.env['o2m.1.model.name'].new({
'o2m_1_field_name': 'value',
'o2m_1_field_o2m_2_name': [{'o2m_2_field': 'value'}]
})
if this is not working for you and giving you bad query error then you need to
use the latest version of odoo 8 because a lot has been changing you can even
do onchange on a o2m_field now ...

Related

Django Rest Framework: Disable save in update

It is my first question here, after reading the similar questions I did not find what I need, thanks for your help.
I am creating a fairly simple API but I want to use best practices at the security level.
Requirement: There is a table in SQL Server with +5 million records that I should ONLY allow READ (all fields) and UPDATE (one field). This is so that a data scientist consumes data from this table and through a predictive model (I think) can assign a value to each record.
For this I mainly need 2 things:
That only one field is updated despite sending all the fields of the table in the Json (I think I have achieved it with my serializer).
And, where I have problems, is in disabling the creation of new records when updating one that does not exist.
I am using an UpdateAPIView to allow trying to allow a bulk update using a json like this (subrrogate_key is in my table and I use lookup_field to:
[
{
"subrrogate_key": "A1",
"class": "A"
},
{
"subrrogate_key": "A2",
"class": "B"
},
{
"subrrogate_key": "A3",
"class": "C"
},
]
When using the partial_update methods use update and this perform_update and this finally calls save and the default operation is to insert a new record if the primary key (or the one specified in lookup_field) is not found.
If I overwrite them, how can I make a new record not be inserted, and only update the field if it exists?
I tried:
Model.objects.filter (subrrogate_key = ['subrrogate_key']). Update (class = ['class])
Model.objects.update_or_create (...)
They work fine if all the keys in the Json exist, because if a new one comes they will insert (I don't want this).
P.S. I use a translator, sorry.
perform_update will create a new record if you passed a serializer that doesn't have an instance. Depending on how you wrote your view, you can simply check if there is an instance in the serializer before calling save in perform_update to prevent creating a new record:
def perform_update(self, serializer):
if not serializer.instance:
return
serializer.save()
Django implements that feature through the use of either force_update or update_fields during save().
https://docs.djangoproject.com/en/3.2/ref/models/instances/#forcing-an-insert-or-update
https://docs.djangoproject.com/en/3.2/ref/models/instances/#specifying-which-fields-to-save
https://docs.djangoproject.com/en/3.2/ref/models/instances/#saving-objects
In some rare circumstances, it’s necessary to be able to force the
save() method to perform an SQL INSERT and not fall back to doing an
UPDATE. Or vice-versa: update, if possible, but not insert a new row.
In these cases you can pass the force_insert=True or force_update=True
parameters to the save() method.
model_obj.save(force_update=True)
or
model_obj.save(update_fields=['field1', 'field2'])

Updating and creating a new instance at the same time

When a user updates an invoice form, i want to create a new invoice record with the updated attributes, but also change one or two fields of the old record and save it, too.
How would the outline of a controller action look like which could accomplish this?
Instead of a controller action i put the code in the model, using callbacks:
before_save do |rec|
if !rec.new_record?
attrb = rec.attributes.delete_if{|k, v| ["id"].include? k }
Book.create(attrb)
rec.restore_attributes
rec.year = rec.year + 2 # some custom change
true
end
end
I keep all attributes unless the 'id' (otherwise i get an error) for create a new record with the new attributes.
Then i restore the attributes of the existing record. I do some custom change before saving.
I am rather new with Rails but this seems pretty straightforward. As you mention the user is 'updating" an invoice, your controller view has probably been passed all the data available to the user for further change.
When submitting the form, your update action can easily update the current record data, as well as creating a new one on top of this
Though as it is automated, you need to make clear:
if a new invoice record is created each time an invoice record is
updated (thi can create a lot of copies of the same invoice)
how you make the old record an archive to avoid duplicates
can the 'additional" amendments be automated and easily processed through an algorithm...
Nested attributes made things a bit tricky. So in order to create new instances I had to use the dup method for both the resource and its nested items.
Generally, it is advisable to keep the controllers slim and make the models fat. Nevertheless, I have decided to include this code into my Invoices controller:
def revise_save
#contact = Contact.find(params[:contact_id])
#invoice = #contact.invoices.find(params[:invoice_id])
#invoice_old = #invoice.dup
#invoice.invoice_items.each do |item|
#invoice_old.invoice_items << item.dup
end
#invoice.datum = DateTime.now.to_date
# archive old invoice
# #invoice_old. ...
#invoice_old.save
# make old new invoice
#invoice.datum = Time.now
# ...
#invoice.update(invoice_params)
redirect_to invoices_path
end
Note that in this solution the currently edited (original) invoice becomes the new invoice, the old one is paradoxically created anew.
Thanks to #iwan-b for pointing me in the right direction.

Adding new line on a one2many computed field with inverse odoo

I have a one2many computed field which i also want users to be able to add new line of records into. i added an inverse field to it, but the only thing it does is to allow already existing records to be modified
#api.one
def accumulate_files(self):
documents = self.env['document.customer']
document_gotten = documents.search([('name','=', self.name)])
for docs in document_gotten:
self.res_line_ids |= docs.customer_line_ids
#api.one
def edit_accumulate_files(self):
documents = self.env['document.customer']
for lines in documents.customer_line_ids:
lines.write(self.res_line_ids)
I did a workaround, not sure how can I get values of one2many field in inverse method, in new api, like it was in old api. however it works for me
#api.multi
def _save_telefone(self):
for partner in self:
for phone in partner.phone_number_ids:
try:
# write on exisiting record
int(phone.id)
# write all possible values
phone.write({'partner_id': partner.id})
except:
# create new record with all possible values
phone.create({
'partner_id': partner.id,
'type_id': phone.type_id.id,
'status_id': phone.status_id.id,
'sequence': phone.sequence,
'graph_value': phone.graph_value,
'name': phone.name,
})
return True
Basically, create a record if it doesn't exist otherwise write on it.
how to know if record exists in DB? if the ID is integer it already
exists, otherwise it will have ID something like "odoo.model.NewID"
that means ID hasn't been assigned yet record is in memory yet.

django one widget for two m2m fields

I have two manytomany fields for my model ModelFrom, that both go to the same Model, call it ModelTo.
ModelFrom(models.Model):
field_one = ManyToManyField(ModelTo)
checked = ManyToManyField(ModelTo)
checked is a subset of field one. I have properly validated this in model clean() and adminform clean() methods, and updated model::save() to call self.full_clean().
Ideally, I would have one widget, much like the django.forms.SelectMultiple, but with a checkbox inside each <option>.
what it currently looks like, I have one of these widgets for each field:
:
I want to combine them and have a checkbox or something, here is my unicode representation of what it would look like
{ [ blah: 2 ☐] , [blah: 1 ☑] }
Value in the list -> field one is set. Checked box -> checked is set as it is a subset of field_one.
I have seen jQuery UI MultiSelect Widget but there doesn't seem to be a way to be able to select an option, but not check the box.
I couldn't directly answer my own question, but like most questions, if the answer is not possible then there may be an underlying problem.
Instead of having two many2many fields, I should just have one, setting the through property, for an intermediate field.
Like so:
class IntermediateField(models.Model):
checked = BooleanField()
from = ForeignKey(ModelFrom)
to = ForeignKey(ModelTo)
ModelFrom(models.Model):
field_one = ManyToManyField(ModelTo, through=IntermediateField)
Then, we can just use an inline for IntermediateField in ModelFrom admin, easily checking the boxes etc

symfony 1.4 and propel - foreign constraints fails saved relation

I am working in a Symfony 1.4 project with Propel 1.4.2.
I have 2 related tables. workshop and trainers which is a many to many relation mapped by a join table (workshop_trainers) which contains the workshop_id and the trainer_id).
In my Workshop Form I have a select box for adding the trainers to the workshop. The problem is when the workshop is new (Create) I get an error:
Cannot add or update a child row: a foreign key constraint fails
This happens because, when saving the workshop_trainers relation the workshop_id field is null. Isn´t Propel intelligent enough to know that there is a relation between the tables and save the base object first? What I am doing wrong?
My trainer list widget.
$this->widgetSchema['workshop_trainer_list'] = new sfWidgetFormChoice(array(
'choices' => $trainers,
'multiple' => true,
));
Thanks for your help.
This is not fixing the problem but that's the easiest practical solution to this problem:
In the form, simply deactivate the workshop_trainer_list field if the object is a new one (doesn't have an ID yet).
Something like:
if ($this->getObject()->isNew())
{
$this->offsetUnset('workshop_trainer_list'); // not sure of that method name
}
A better solution is to update the doSave method to have the ID first, something like this:
protected function doSave($con = null)
{
$isNew = $this->getObject()->isNew();
if (null === $con)
{
$con = $this->getConnection();
}
// retrieve the value of workshop_trainer_list here and remove it from the form
$trainers = ...
$this->offsetUnset('workshop_trainer_list');
// save without it
parent::doSave($con);
// add it back
$this->getObject()->set...
// save
$this->getObject()->save($con);
}