I have this many2one field that I want to get the ID of the selected value
service = fields.Many2one('mainservices.mtvehlog', string='Select Service(s)')
so onchange i want to know the id and do something after knowing (I want to make other fields invisible)
What if the many2one is multi selection? How do you get the ID's that have been selected?
#api.depends('service')
def _compute_hide(self):
source_obj=self.pool.get('mainservices.mtvehlog').browse(self.service)
if source_obj == '1':
self.services_selected = source_obj
self.hide = True
else:
self.services_selected = source_obj
self.hide = False
kindly help
In compute methods using depends decorator always loop throuth self first.
for rec in self:
# and this is how you get the id value
#you don't have to browse you have direct acces to properties of the selected value
if rec.service.id == somthing :
# and you will not get except singlton error
you question is not clear what you want to do with the id value exactly.
Related
I have a many2one field as A and one2many field as A_details that A_details has filter base on A,
A = fields.Many2one(comodel_name="headertable")
A_details = fields.One2many(comodel_name="detailtable")
and in the xml I pass the A value with context in A_detail to filter it
<field name="A_detail" context="{'parent_id': A,}"/>
now I want to delete A_detail's records when user changes the A value, so I use onchange decorator on A field like this:
#api.onchange('A')
def _delete_selected_records(self):
for rec in self.A_details:
self.A_details = [(3, rec.id, 0)]
this function workes correctly to create mode but the problem occurs when I open the record from tree view and while A field is getting value from model Onchanged decorator call the _delete_selected_records function and it delete all the A_detail's records, That's why I want to check in this function that if user change the A, delete the A_detail's records else if system sets value to field do nothing... how can I handle this???
You should add a check if A is deleted or not meaning if A is False then do X:
#api.onchange('A')
def _delete_selected_records(self):
for rec in self:
if rec.A is False:
rec.A_details = [(3, rec.id, 0)] # You can you .unlink() btw
else:
continue
This way even if the function is triggered by let's say a user accidentally putting cursor on the field in the view or something you won't risk deleting anything unless the correct condition is met.
I have a list of tasks related to a project in a one-to-many relationship one project have many tasks, reading the official documentation the field access should be as easy as iterating on a list and access the field by name, this is the code I have done so far:
def _roles_assigned(self):
for rec in self:
total = len(rec.task_ids)
for e in rec.tasks
logging.info(e.status) #<-- this should print status
I print the result and get 'project.task(X,)' where I guess X is the Id of the task, how can I access the task properties?
Note: the field is a selection field
try something like this:
def _roles_assigned(self):
for tasks in self.task_ids:
logging.info(tasks.status)
Since the field is a selection I had to access the dictionary
#api.multi
#api.depends('task_ids')
def _roles_assigned(self):
for rec in self:
total = len(rec.tasks)
assigned = 0
for e in rec.tasks:
selected = dict(e._fields['status'].selection).get(e.status) #<-- getting selected value from a selection field
I am trying to get the old value of a field in onchange method.
Here is what I tried.
#api.onchange('assigned_to')
# #api.depends('assigned_to')
def onchange_assigned_to(self):
print('onchange_assigned_to')
history = self._origin.read(["assigned_to"])
if history:
id = history[0]["assigned_to"][0]
last_assigned = self.env['res.users'].browse([id])
self.last_assign_id = last_assigned
The above code is working and I getting the old value only if I change the field value through GUI.
I am also changing the field value via button action., that time this function is not working.
How can I achieve this?
And I also tried on compute function with #api.depends.
That time I got an
'AttributeError: 'crm.lead' object has no attribute '_origin''
You can implement this in write method, and will always work, you can keep the onchange
if you want to give a feedback to the user:
#api.multi
def write(vals):
""" keep assignment history. """
if 'assigned_to' in vals: # keep assignment history
# no need to keep it in vals here
vals.pop('last_assign_id', None)
for rec in self:
rec.last_assign_id = rec.assigned_to
return super(ClassName, self).write(vals)
Hi i am trying to delete a key value from the context for res.partner form view.
I opening the partner form view using controller function and trying to set phone number as default and its working fine. But when i try to create a new customer by clicking on the create button the phone number again auto-filled. In order to avoid this behaviour, in default_get function, i copied the context into another variable, removed the key value from the context using del context['cc_mobile']. And reassigned to self.env.context. But when i try to create a new customer, the deleted key value comes in the context again.
Controller.py
#http.route('/open_customer/<string:val>', type="http",method=['POST','GET'],website=False, auth="public")
def open_case_window(self,**kw):
mobile_no = kw.get('val')
action = request.env.ref('base.action_partner_form').sudo()
mobile_flag = 0
partner = 'res.partner'
partner_model = request.env[partner]
regex = re.match( '^(?:\01|02|03|04|06|07|09)\d*$', mobile_no)
if regex:
mobile_flag = 0
partner_id = partner_model.search([('phone', '=', mobile_no)]).id
else:
mobile_flag = 1
partner_id = partner_model.search([('mobile','=',mobile_no)]).id
if partner_id:
return werkzeug.utils.redirect('/web#id='+str(partner_id)+'&view_type=form&model='+partner)
else:
context = dict(action._context)
if mobile_flag == 0:
context.update({'cc_phone': mobile_no})
else:
context.update({'cc_mobile': mobile_no})
context.pop('lang')
url = werkzeug.utils.redirect('/web?debug=#view_type=form&model='+str(partner)+'&action=%s'%(action.id))
return url
ResPartner.py
#api.model
def default_get(self, fields):
context = self.env.context.copy()
print'default_get context',context
res = super(Partner, self).default_get(fields)
if 'cc_mobile' in context:
res.update({'mobile':context.get('cc_mobile')})
if 'cc_phone' in context:
res.update({'phone':context.get('cc_phone')})
if context.get('cc_mobile'):
del context['cc_mobile']
if context.get('cc_phone'):
del context['cc_phone']
self.env.context = context
print'self.env.context after',self.env.context
action = self.env.ref('base.action_partner_form').sudo()
action.env.context = self.env.context
return res
You cannot remove a key of action context from python side, because it's in the client side. when ever you call the server like search in many2one field, create a record in fly you will see this context comeback again every time (The way Odoo work).
What you need is something that will be used for one time, I think you need some kind of persistence for example:
dummy model that contains user_id, model_name, value, active fields so in the controller you create a record for default value for that specific user.
get that value by overriding default_get by searching with user_id and model_name field and hide that value or delete it.
this way when yo hit create button or create contact in fly when you search for the value it will be gone so it will not be used a second time.
This a simple Idea and easy to implement, you need to handle some cases to prevent user from saving two default value if some interruption happens should not be hard.
Edit
After second thought to prevent any error when you create a record just pass it's ID in the context with a special key, then use That Id to retrieve it, use it then delete it. easier, safer and no need for search.
I wanna a user to create a record but later dun give it the right to change the value of that field. should I do it By overriding create and write methods? is it possible to write such code:
field1: fields.float(string='Field',write=['base.GROUP_ID']),
This may work create a status field this field is a compute field when it's true the field1 will be read only. Because i'm on my phone i'm not going to writr the hole code just try to understand the idea
status = field.Boolean(compute='compute_status')
def compute_status(self):
for rec in self:
# first check of the use belong to the group that have full acces
if self.env.user.has_group('group_id') :
rec.status = False
# then check if the record is saved in databse
# unsaved records There id is instance of NewId it's a dummy class used for this
elif instanceOf(NewId ,rec.id) :
rec.status = False # here all users can fill the field when the record is not created yet but cannot edit
else :
rec.status = True # if record is saved and user is not in group_id make field readonly or invisible as you want
Now create your field and use status property to make it readonly when status field is True .
As you can see my answer is algorithme more than a code sorry for sysntax errors
I think the better way to do this is to create a group to which the user will belong, then set in the ir.model.access a rule, with the rights you want, for that particular group.
Ask if you need more help.
EDIT
You can define a view, that inherit from the original one, but is accessible only for the user group, like:
<field name="groups_id" eval="[(6, 0, [ref(' < your group > ')])]"/>
and there you redefine the field making it readonly. That's it.