How to search product by field in different table - python

I want to use name_search in product to get product by search the lot name which in stock.production.lot
relation stock_quant_ids,product_id,lot_id
class ProductProduct(models.Model):
_inherit = 'product.product'
#api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
args = args or []
print('arg ',args)
recs = self.search([('???', operator, name)] args, limit=limit) #stock_quant_ids.lot_id.name
print('recs ', recs)
if not recs.ids:
return super(ProductProduct, self).name_search(name=name, args=args,
operator=operator,
limit=limit)
return recs.name_get()

Try this:
#api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
""" search for product using the Lot number """
args = args or []
recs = None
# only perform search by when the name is passed
if name:
# don't use limit here
recs = self.env['stock.production.lot'].search([('name', operator, name)])
if recs:
# handle extra filter that was passed by the domain attribute in the XML
args = expression.AND([args, [('id', 'in', recs.mapped('product_id').ids)]])
return self.search(args, limit=limit).name_get()
# no Lot was founded may be the user meant to search by product name
return super(ProductProduct, self).name_search(name=name,
args=args,
operator=operator,
limit=limit)

Related

How to add search other field in many2one?

HI I have a customer field and the default search is by name, and I want to add a search by barcode as well to the customer field
I have tried adding a barcode(partner_id.barcode) on the domain as below, but it still doesn't work (model = sale.order)
#api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if self._context.get('sale_show_partner_name'):
if operator == 'ilike' and not (name or '').strip():
domain = []
elif operator in ('ilike', 'like', '=', '=like', '=ilike'):
domain = expression.AND([
args or [],
['|', '|', ('name', operator, name), ('partner_id.name', operator, name), ('partner_id.barcode', operator, name)]
])
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
return super(SaleOrder, self)._name_search(name, args=args, operator=operator, limit=limit, name_get_uid=name_get_uid)
I have also tried in the (res.partner) model as below. it can search customer by barcode, but cannot search customer by name :
#api.model
def name_search(self, name, args=None, operator='ilike', limit=100):
if not self.env.context.get('display_barcode', True):
return super(ResPartnerInherit, self).name_search(name, args, operator, limit)
else:
args = args or []
recs = self.browse()
if not recs:
recs = self.search([('barcode', operator, name)] + args, limit=limit)
return recs.name_get()
What should I do if I want to find a customer by name and barcode?
If anyone knows, please let me know
Best Regards
The barcode field in res.partner is a property field and stored in ir.property model which name is Company Propeties in Odoo and you can access it with developer mode from Settings -> Technical -> Company Propeties.
The _name_search method for res.partner enable you to search in any Many2one partner relation field in any model by one of these fields display_name, email, reference and vat and you can override it to add barcode as below:
from odoo import api, models
from odoo.osv.expression import get_unaccent_wrapper
import re
class ResPartner(models.Model):
_inherit = 'res.partner'
#api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
self = self.with_user(name_get_uid) if name_get_uid else self
# as the implementation is in SQL, we force the recompute of fields if necessary
self.recompute(['display_name'])
self.flush()
print(args)
if args is None:
args = []
order_by_rank = self.env.context.get('res_partner_search_mode')
if (name or order_by_rank) and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
self.check_access_rights('read')
where_query = self._where_calc(args)
self._apply_ir_rules(where_query, 'read')
from_clause, where_clause, where_clause_params = where_query.get_sql()
from_str = from_clause if from_clause else 'res_partner'
where_str = where_clause and (" WHERE %s AND " % where_clause) or ' WHERE '
print(where_clause_params)
# search on the name of the contacts and of its company
search_name = name
if operator in ('ilike', 'like'):
search_name = '%%%s%%' % name
if operator in ('=ilike', '=like'):
operator = operator[1:]
unaccent = get_unaccent_wrapper(self.env.cr)
fields = self._get_name_search_order_by_fields()
query = """SELECT res_partner.id
FROM {from_str}
LEFT JOIN ir_property trust_property ON (
trust_property.res_id = 'res.partner,'|| {from_str}."id"
AND trust_property.name = 'barcode')
{where} ({email} {operator} {percent}
OR {display_name} {operator} {percent}
OR {reference} {operator} {percent}
OR {barcode} {operator} {percent}
OR {vat} {operator} {percent})
-- don't panic, trust postgres bitmap
ORDER BY {fields} {display_name} {operator} {percent} desc,
{display_name}
""".format(from_str=from_str,
fields=fields,
where=where_str,
operator=operator,
email=unaccent('res_partner.email'),
display_name=unaccent('res_partner.display_name'),
reference=unaccent('res_partner.ref'),
barcode=unaccent('trust_property.value_text'),
percent=unaccent('%s'),
vat=unaccent('res_partner.vat'), )
where_clause_params += [search_name] * 4 # for email / display_name, reference
where_clause_params += [re.sub('[^a-zA-Z0-9\-\.]+', '', search_name) or None] # for vat
where_clause_params += [search_name] # for order by
if limit:
query += ' limit %s'
where_clause_params.append(limit)
print(query)
print(where_clause_params)
self.env.cr.execute(query, where_clause_params)
return [row[0] for row in self.env.cr.fetchall()]
return super(ResPartner, self)._name_search(name, args, operator=operator, limit=limit, name_get_uid=name_get_uid)

How to override a Model Form widget in Django?

I'm trying to override render_option method present inside Select Widget class from my forms.py file. So I have added the method with the same name inside the corresponding Model form class. But it won't work (this method fails to override). My forms.py file looks like,
class CustomSelectMultiple(Select):
allow_multiple_selected = True
def render_option(self, selected_choices, option_value, option_label):
print 'Inside custom render_option\n\n'
if option_value is None:
option_value = ''
option_value = force_text(option_value)
if option_value in selected_choices:
selected_html = mark_safe(' selected="selected"')
if not self.allow_multiple_selected:
# Only allow for a single selection.
selected_choices.remove(option_value)
else:
selected_html = ''
return format_html('<option value="{}" data-img-src="www.foo.com" {}>{}</option>',
option_value,
selected_html,
force_text(option_label))
def render_options(self, choices, selected_choices):
print 'Inside custom render_options\n\n'
print self
print choices
# Normalize to strings.
selected_choices = set(force_text(v) for v in selected_choices)
output = []
for option_value, option_label in chain(self.choices, choices):
if isinstance(option_label, (list, tuple)):
output.append(format_html('<optgroup label="{}">', force_text(option_value)))
for option in option_label:
output.append(self.render_option(selected_choices, *option))
output.append('</optgroup>')
else:
output.append(self.render_option(selected_choices, option_value, option_label))
#print output
return '\n'.join(output)
def render(self, name, value, attrs=None, choices=()):
print 'Inside custom render\n\n'
if value is None:
value = []
final_attrs = self.build_attrs(attrs, name=name)
output = [format_html('<select multiple="multiple"{}>', flatatt(final_attrs))]
options = self.render_options(choices, value)
if options:
output.append(options)
output.append('</select>')
return mark_safe('\n'.join(output))
def value_from_datadict(self, data, files, name):
if isinstance(data, MultiValueDict):
return data.getlist(name)
return data.get(name)
class GuideUpdateForm(ModelForm):
def __init__(self, *args, **kwargs):
super(GuideUpdateForm, self).__init__(*args, **kwargs)
self.fields['date_modified'].widget = HiddenInput()
self.fields['point_of_interest'].widget = CustomSelectMultiple()
class Meta:
fields = ('name', 'image', 'point_of_interest', 'date_modified', )
model = Guide
I also tried changing my Meta class like,
class Meta:
fields = ('name', 'image', 'point_of_interest', 'date_modified', )
model = Guide
widgets = {
'point_of_interest': SelectMultiple(attrs={'data-img-src': 'www.foo.com'}),
}
But it add's the attribute data-img-src only to the select tag but not to all the option tags present inside the select tag.
Note that SelectMultiple class invokes the renderoptions method of Select class which further invokes the renderoption method which don't have attrs=None keyword argument.
Judging off your own solution it looks like you may have been looking for a ModelChoiceField
self.fields['point_of_interest'] = forms.ModelChoiceField(widget=CustomSelectMultiple(),
queryset=poi.objects.all())
The queryset parameter consists of "A QuerySet of model objects from which the choices for the field will be derived, and which will be used to validate the user’s selection."
does it create a list of tuples of ids, names? Because I want the option tag to look like option value="id">name</option>
I'm pretty sure the default is id, __str__ where __str__ is the string representation of the model. If you wanted this to be specific to the name then you could override this field and set label_from_instance
class MyModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return obj.name
I managed to solve this problem by passing db values to choices kwargs.
from models import poi
class GuideUpdateForm(ModelForm):
def __init__(self, *args, **kwargs):
super(GuideUpdateForm, self).__init__(*args, **kwargs)
self.fields['date_modified'].widget = HiddenInput()
self.fields['point_of_interest'] = forms.ChoiceField(widget=CustomSelectMultiple(), choices=[(i.id,i.name) for i in poi.objects.all()])

Error occured while overriding the search function of a class in openerp

I tried to override search function of class 'project' to filter the projects.But its not give a list, which i need. It just load all value from the model . From where I need to pass the context.Below given is my code
class project(osv.osv):
_name = "project.project"
_description = "Project"
_inherits = {'account.analytic.account': "analytic_account_id",
"mail.alias": "alias_id"}
def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
if user == 1:
return super(project, self).search(cr, user, args, offset=offset, limit=limit, order=order, context=context, count=count)
if context and context.get('user_preference'):
cr.execute("""SELECT project.id FROM project_project project
LEFT JOIN account_analytic_account account ON account.id = project.analytic_account_id
LEFT JOIN project_user_rel rel ON rel.project_id = project.id
WHERE (account.user_id = %s or rel.uid = %s)"""%(user, user))
return [(r[0]) for r in cr.fetchall()]
return super(project, self).search(cr, user, args, offset=offset, limit=limit, order=order,
context=context, count=count)
_columns = {
'members': fields.many2many('res.users', 'project_user_rel', 'project_id', 'uid', 'Project Members',
help="Project's members are users who can have an access to the tasks related to this project.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
}
You need to pass it from xml code. It should be many2one with project.project and add the context like context="{'test': 'yes'}" in xml file where you define this field like this:
<field name="project_id" context="{'test': 'test'}"/>
By overriding search method of project.project, check this context. Now you should get this context in search method.
If you get this context, fire your query, get the result accordingly it and return it as list of ids. If you don't get, return super method of project.project as specified in the code. Also, remove the condition of if user==1 as per your need, you do not require it otherwise it will come up with all list of projects.

ValueError: SQL query parameters should be a tuple, list or dict

Edited code in a correct way. Now it's working.
Here is my code:
def _random_letter(self, cr, uid, ids, name, args, context):
num=[]
for i in range(5):
res = random.choice([1, 2, 3, 5, 9])
num.append(res)
print (num)
return num
def _mytest_query(self, cr, uid, ids, name, args, context):
cr.execute("""update checkroll_plucker set worker_name =concat('worker','%s') where id='1'""", self._random_letter(cr, uid, ids, name, args, context))
cr.commit()
Also, I am still confused about which parameters to pass to functions. I go through a developer book, but haven't got clear idea. I will mention those below please correct me if they correct.
Example:
self, cr, uid, ids, name, args, context
self = call to current class of that method called
cr = current row in the table
uid = user id for check if he authorized or not for run this function
name = column name we need to insert
context = language/time details (but what is the use of it.more times it equals to None)
put
self._random_letter in (,)
Repair Bug
cr.execute("""update checkroll_plucker set worker_name =concat('worker','%s') where id='1'""", (self._random_letter,)(cr, uid, ids, name, args, context))
To pass parameters in tuples , That is to use (arg,)

Google App Engine: get_or_create()?

Does Google App Engine have an equivalent of Django's get_or_create()?
There is no full equivalent, but get_or_insert is something similar. The main differences is that get_or_insert accepts key_name as lookup against filters set in get_or_create.
Haven't tested this, but it should be something like the following:
class BaseModel(db.Model):
#classmethod
def get_or_create(cls, parent=None, **kwargs):
def txn():
query = cls.all()
if parent:
query.ancestor(parent)
for kw in kwargs:
query.filter("%s =" % kw, kwargs[kw])
entity = query.get()
if entity:
created = False
else:
entity = cls(parent, **kwargs)
entity.put()
created = True
return (entity, created)
return db.run_in_transaction(txn)
class Person(BaseModel):
first_name = db.StringProperty()
last_name = db.StringProperty()
p, created = Person.get_or_create(first_name='Tom', last_name='Smith')

Categories

Resources