Change other fields value during validation with Formalchemy? - python

Writing custom validators for Formalchemy is simple. During the validation of SOMEFIELD I can access another fields value using field.parent.SOMEOTHERFIELD.value.
Is it possible to change SOMEOTHERFIELD's value during the validation of SOMEFIELD? Or should I separate changing related field values from the validation process altogether?

gawel's answer was a step but did not solve my problem (see comment under his answer). I changed the value of field.parent.model.SOMEOTHERFIELD but the change was not committed to the db with session.commit().
After trying out many things I found out that you must use fieldset.sync() before field.parent.model.SOMEOTHERFIELD = value. Only then the change is committed.

You can use field.parent.model.SOMEOTHERFIELD = value

Related

Odoo 13 : Loading never end when updating module (when set default field or set store=True in model that has so many data)

let's say that i have so many data in hr_attendance module.
in that module has field like this :
distance_string = fields.Char(string='Distance', compute='_compute_range')
then i change distance_field and add new field to :
distance_string = fields.Char(string='Distance', compute='_compute_range', store=True)
outside_range= fields.Selection([('no','no'),('yes','Yes')], string="Out of Range", default='no')
the problem is because of so many datas in my model (maybe 270000+ datas). When i update the module (hr_attendance) in app menu in ODOO13, it takes so much loading time to install and then it always fail.
I assumed that because of so many data in my model, when i only add outside_range field without default='no' it works fine.
my question is how to handle this condition (when i need to set store=True and add default='' in model that has so many data)?
thanks for your help

is there an easier way to either create or re-write exist object? django

I know in django we can create an object model easily by using something like this
AbcModel.objects.create(field1='a', field2='b')
But this would create the object even if it already exists.
I know I can use filter() then use the exist() to check if the object already exist then decide to update or create.
But is there an easier and faster way to do this? Since, there is get_or_create so I am curious if there's something similar.
Thanks in advance
EDIT:
I thought of something like this
new = AbcModel.objects.create(field1='a')
new[0].field2 = 'c'
new[0].save()
There might be more fields and field1 will not always be a would be others like b, c and maybe a again.
Just being curious if there is an easier faster way and not saying get_or_create wouldn't get what I want / need
As you said about get_or_create, you could do:
abc_instance, created = AbcModel.objects.get_or_create(field1='a', field2='b')
That would bring you the existent/created object as the first argument and a boolean as the second argument, that defines if it was got or created.
Additionally, field1 and field2 will be used for the filter, but you can set the defaults attribute, which will update the existing entry or be used for its creation.
abc_instance, created = AbcModel.objects.get_or_create(
field1='a', field2='b',
defaults={'field3': 'c', 'field4': 'd'}
)
You can use update_or_create: https://docs.djangoproject.com/en/2.0/ref/models/querysets/#update-or-create
However if the field you filter by is not unique, you might end up getting a MultipleObjectsReturned exception.
Another way to do this could be:
num_updated = AbcModel.objects.filter(field1='a').update(field2='c')
if num_updated == 0:
model = AbcModel.objects.create(field1='a', field2='c')
In num_updated you will have the number of rows updated in the first line of code.
I hope this helps a bit!

Odoo v9 - Using Onchange, how do you clear what is already entered in a field?

I am extending product.template, and I've added a field called uom_class. When I change this field when editing a product, I'd like to clear what is entered in the Many2One field called "Unit of Measure" (uom_id in product.template). I am doing this because I am also changing the domain for the uom_id, and the existing selection ("Units" by default) will probably not be in that domain.
I've tried the following, as suggested for earlier versions, but it did not work.
#api.onchange('uom_class')
def onchange_uom_class(self):
# [...] not shown: previously set new domain for uom_id
result['value'] ={'uom_id':False}
return result
I've seen other posts suggest I need to add assign it an empty product.uom record, but I have no idea how to do that. Any help would be greatly appreciated.
Well, I figured this one out.
I just declared
uom_id = False
For some reason, returning the domain works, but not returning the value. Either that, or I just have no idea what I'm doing and I'm returning the value wrong... which is entirely possible.

Django form: restore predefined field value in clean method

In my Django form I need to perform different field values comparisons (+ some additional checks). If all of these conditions are met I want to raise error and inform user that he can't perform this operation. Right now I'm doing it in clean method and code looks like these:
if self.instance.foo != cleaned_data['foo'] and \
Bar.objects.filter(baz=self.instance.id).count():
cleaned_data['foo'] = self.instance.foo
raise forms.ValidationError("You can't change it")
That's working fine, but I'd also like to reject the change and restore previous value (before the update). The assignment cleaned_data['foo'] = self.instance.foo obviously is not working because cleaned_data is not being returned due to raising ValidationError. How can I achieve this?
It turned out that you can access fields' values via self.data. So I ended up doing self.data['foo'] = self.instance.foo and it's working now.

Re evaluate django query after changes done to database

I got this long queryset statement on a view
contributions = user_profile.contributions_chosen.all()\
.filter(payed=False).filter(belongs_to=concert)\
.filter(contribution_def__left__gt=0)\
.filter(contribution_def__type_of='ticket')
That i use in my template
context['contributions'] = contributions
And later on that view i make changes(add or remove a record) to the table contributions_chosen and if i want my context['contributions'] updated i need to requery the database with the same lenghty query.
contributions = user_profile.contributions_chosen.all()\
.filter(payed=False).filter(belongs_to=concert)\
.filter(contribution_def__left__gt=0)\
.filter(contribution_def__type_of='ticket')
And then again update my context
context['contributions'] = contributions
So i was wondering if theres any way i can avoid repeating my self, to reevaluate the contributions so it actually reflects the real data on the database.
Ideally i would modify the queryset contributions and its values would be updated, and at the same time the database would reflect this changes, but i don't know how to do this.
UPDATE:
This is what i do between the two
context['contributions'] = contributions
I add a new contribution object to the contributions_chosen(this is a m2m relation),
contribution = Contribution.objects.create(kwarg=something,kwarg2=somethingelse)
user_profile.contributions_chosen.add(contribution)
contribution.save()
user_profile.save()
And in some cases i delete a contribution object
contribution = user_profile.contributions_chosen.get(id=1)
user_profile.contributions_chosen.get(id=request.POST['con
contribution.delete()
As you can see i'm modifying the table contributions_chosen so i have to reissue the query and update the context.
What am i doing wrong?
UPDATE
After seeing your comments about evaluating, i realize i do eval the queryset i do
len(contributions) between context['contribution'] and that seems to be problem.
I'll just move it after the database operations and thats it, thanks guy.
update
Seems you have not evaluated the queryset contributions, thus there is no need to worry about updating it because it still has not fetched data from DB.
Can you post code between two context['contributions'] = contributions lines? Normally before you evaluate the queryset contributions (for example by iterating over it or calling its __len__()), it does not contain anything reading from DB, hence you don't have to update its content.
To re-evaluate a queryset, you could
# make a clone
contribution._clone()
# or any op that makes clone, for example
contribution.filter()
# or clear its cache
contribution._result_cache = None
# you could even directly add new item to contribution._result_cache,
# but its could cause unexpected behavior w/o carefulness
I don't know how you can avoid re-evaluating the query, but one way to save some repeated statements in your code would be to create a dict with all those filters and to specify the filter args as a dict:
query_args = dict(
payed=False,
belongs_to=concert,
contribution_def__left__gt=0,
contribution_def__type_of='ticket',
)
and then
contributions = user_profile.contributions_chosen.filter(**query_args)
This just removes some repeated code, but does not solve the repeated query. If you need to change the args, just handle query_args as a normal Python dict, it is one after all :)

Categories

Resources