Odoo on write() method check many2many relation - python-2.7

I have 2 classes:
class my_request(models.Model):
_name = 'my.request'
_inherit = ['mail.thread', 'ir.needaction_mixin']
supply_ids = fields.Many2many(comodel_name='supply.conditions',
relation='purchase_supply_rel',
column1='purchase_requests_id', column2='supply_conditions_id',
string='Supply Conditions')
and
class SupplyConditions(models.Model):
_name = 'supply.conditions'
vendor = fields.Char(string='Vendor', required=True)
quantity = fields.Char(string='Quantity', required=True)
request_id = fields.Many2one('my.request', 'My request')
name = fields.Many2one('my.request.line', string='Product', required=True)
currency_id = fields.Many2one('res.currency', string='Currency', default=_get_default_currency)
supply_rel_id = fields.Boolean(string='Relation field', default=False)
my.request class part of form view xml:
<page string="Order">
<field name="supply_ids" domain="[('purchase_id', '=', id)]"/>
</page>
When I select values from my.request form view and click on Save button I call write() method and at that time insert m2m values (if there is selected values) into relational table (purchase_supply_rel).
I want to add check if purchase.request id is in purchase_supply_rel table in purchase_requests_id field when I click on Save button. My function. Changes after # my new code coment:
#api.multi
def write(self, vals):
res = super(PurchaseRequest, self).write(vals)
for request in self:
if request.state != 'draft':
if vals.get('assigned_to'):
self.message_subscribe_users(user_ids=[request.assigned_to.id])
# my new code
test = self.env['purchase.request'].search([(self.id,'in','supply_ids')])
_logger.warning("test " + str(test));
return res
But I got an error:
File "/opt/odoo/openerp/osv/expression.py", line 586, in check_leaf
raise ValueError("Invalid leaf %s" % str(self.leaf))
ValueError: Invalid leaf (348, 'in', 'supply_ids')
How else I can check this? And what I am doing wrong?
UPDATE:
I need to get test value smth like this: purchase_request(245,352)
245,352 - ids of purchase.request class

You can not add dynamic value in domain in place of field name.
Domain is a list of tuples. Domain contains three portions in tuple.
Domain:
[('field_name','operator','values')]
So dynamic value is not allowed in field name in domain.
#api.multi
def write(self, vals):
res = super(PurchaseRequest, self).write(vals)
for request in self:
if request.state != 'draft':
if vals.get('assigned_to'):
self.message_subscribe_users(user_ids=[request.assigned_to.id])
# my new code
test = self.env['purchase.request'].search([('supply_ids','in',self.ids)])
_logger.warning("test " + str(test));
return res

Related

Queryset takes too long to populate data

I have a django view that generates a form depending on POST or GET. It works well with little data on the Student model but stagnates when the data gets big. Is there a remedy I can apply??
Here's the view
def My_View(request,pk):
if request.method == 'POST':
try:
form = NewIssueForm(request.POST,school= request.user.school,pk=pk,issuer = request.user)
if form.is_valid():
name = form.cleaned_data['borrower_id'].id
form.save(commit=True)
books = Books.objects.get(id=pk)
Books.Claimbook(books)
return redirect('view_books')
messages.success(request,f'Issued successfully')
except Exception as e:
messages.warning(request,f"{e}")
return redirect('view_books')
else:
form = NewIssueForm(school= request.user.school,pk=pk,issuer = request.user)
return render(request, 'new_issue.html', {'form': form})
Here's the form
class NewIssueForm(forms.ModelForm):
def __init__(self,*args, pk,school,issuer, **kwargs):
super(NewIssueForm, self).__init__(*args, **kwargs)
booqs = Books.objects.filter(school=school).get(id=pk)
self.fields['issuer'].initial = issuer
self.fields['borrower_id'].Student.objects.filter(school = school)
self.fields['book_id'].label = str(booqs.book_name) + " - " + str(booqs.reg_no)
self.fields['book_id'].initial = pk
class Meta:
model = Issue
fields = ['issuer','book_id','borrower_id','due_days']
widgets = {
'book_id':forms.TextInput(attrs={"class":'form-control','type':''}),
'issuer':forms.TextInput(attrs={"class":'form-control','type':'hidden'}),
'borrower_id': Select2Widget(attrs={'data-placeholder': 'Select Student','style':'width:100%','class':'form-control'}),
'due_days':forms.TextInput(attrs={"class":"form-control"}),
Student model
class Student(models.Model):
school = models.ForeignKey(School, on_delete=models.CASCADE)
name = models.CharField(max_length=200,help_text="The student's name in full")
now = datetime.datetime.now()
YEAR = [(str(a), str(a)) for a in range(now.year-5, now.year+1)]
year = models.CharField(max_length=4, choices = YEAR,help_text='The year the student is admitted in school')
student_id = models.CharField(max_length=40,help_text = "This is the student's admission number")
klass = models.ForeignKey(Klass,on_delete=models.CASCADE)
stream = models.ForeignKey(Stream,on_delete=models.CASCADE)
graduated = models.BooleanField(default=False,help_text = "Tick the box to mark the student as graduated")
prefect = models.BooleanField(default=False,help_text = "Tick the box to select the student as a prefect")
def __str__(self):
return "%s - %s - F%s %s"%(self.student_id,self.name,self.klass,self.stream)
class Meta:
verbose_name_plural = 'Students'
unique_together = ("school", "student_id",)
indexes = [models.Index(fields=['student_id']),
models.Index(fields=['name', ]),
The reason this happens is because when you render the Student, it will need to fetch the related Klass and Stream objects, and will make a query per Student object. This problem is called an N+1 problem since fetching n student requires one query to fetch all the Students, and then one query per Student for the Klasses, and one query per Student for the Streams.
You can select the data when you select the students with:
self.fields['borrower_id'].Student.objects.filter(
school=school
).select_related('klass', 'stream')
Depending on the __str__ implementations of other models, you might have to select data along with these models as well.
Can't guess your model but it seems like select_related may play a trick.

Working with List of numbers in Django

I have a loop of buttons, ranging from 1-100 (this varies, could be 1-50), if a user selects any of the button it populates an input field e.g 32, 47, 84, 69.
So i have a django view that saves it to the database but it is saved in the database in this format [u'32', u'47', u'84', u'69'] which i know will be regarded as one entity, but i need the numbers to be regarded as separate entity, so that any number that is in the database, wont be selected by any other user.
def game_details(request, id):
template_name = 'app_agent_games/game_details.html'
get_game_id = get_object_or_404(gamesModel, id=id)
context = {
'game_details': get_game_id,
'range': range(1, get_game_id.people + 1)
}
if request.POST:
guesses = request.POST.get('guessed_number', False)
splited = guesses.split(',')
counter = request.POST.get('count_guess', False)
update_game = PlayGameForm(request.POST)
obj = PlayGame()
obj.guessed_number = splited
obj.total_stake = int(get_game_id.amount) * int(counter)
obj.game_id = get_object_or_404(gamesModel, id=id)
obj.agent_id = get_object_or_404(CustomAgent, user_id=request.user.user_id)
obj.save()
return HttpResponseRedirect('/games/details/'+id)
return render(request, template_name, context)
The model structure:
class PlayGame(models.Model):
agent_id = models.ForeignKey(CustomAgent, related_name='agent_game')
game_id = models.ForeignKey(gamesModel, related_name='agent_game_id')
guessed_number = models.CharField(max_length=100)
total_stake = models.IntegerField(default=0)
The model field that saves the list is guessed_number
Sounds like you need a slightly more evolved data model:
class PlayGame(models.Model):
agent_id = models.ForeignKey(CustomAgent, related_name='agent_game')
game_id = models.ForeignKey(gamesModel, related_name='agent_game_id')
total_stake = models.IntegerField(default=0)
class GameNumber(models.Model):
game = models.ForeignKey(PlayGame)
number = models.IntegerField()
user = models.ForeignKey('YourUser', blank=True, null=True)
Then, for example, you create all your numbers 1-100 for your game, and if a user guessed it, set the user FK to be the user who guessed it, else keep the user FK null.

Customizing the incoming lead to auto fill the fields in lead present in body email

I have customized the lead generation through incoming email by the below code. I am fetching the content of the body in email and matching to the fields present in lead.The template will be same every time but some times the data will not present.
Example; template is Caller Name: abcd
Phone: 1234567891
email: abcd#gmail.com
date :16/12/16
The data in email body will be same everytime but sometimes the email will not present or any other.the email will not generate to lead.I want the condition that above data will present then that fields should fill otherwise left it.
Ca anybody help me how to write that condition
My Code:
def message_new(self, cr, uid, msg, custom_values=None, context=None):
_logger.info("________________________MESSAGE_NEW________________________")
_logger.info(msg.get('subject', ''))
#myString = msg.get('subject', '')
#myString.index('Phone:')
#mobileNumber = myString[myString.index('Phone:')+6:myString.index('Phone:')+16]
myString = html2plaintext(msg.get('body', ''))
_logger.info(myString)
myString.index('Caller Name:')
newstring=myString.split("*")
_logger.info("--------------------------------------------------------")
_logger.info(newstring)
indx=newstring.index('Caller Name:')
mobileNumber = newstring[indx+1]
indx=newstring.index('Caller\nPhone:')
mobile=newstring[indx+1]
indx=newstring.index('City:')
city=newstring[indx+1]
indx=newstring.index('Branch Info:')
branch=newstring[indx+1]
indx=newstring.index('Caller\nEmail:')
emailstr=newstring[indx+1]
emailarr=emailstr.split("[")
email=emailarr[0]
indx=newstring.index('Caller\nRequirement:')
requirement=newstring[indx+1]
indx=newstring.index('Caller\nRequirement:')
requirement=newstring[indx+1]
indx=newstring.index('Call Date &\nTime:')
date=newstring[indx+1]
if context is None:
context = {}
data = {}
if isinstance(custom_values, dict):
data = custom_values.copy()
model = context.get('thread_model') or self._name
model_pool = self.pool[model]
fields = model_pool.fields_get(cr, uid, context=context)
if 'name' in fields and not data.get('name'):
data['name'] = requirement
if 'contact_name' in fields and not data.get('contact_name'):
data['contact_name'] = mobileNumber
if 'city' in fields and not data.get('city'):
data['city'] = city
if 'mobile' in fields and not data.get('mobile'):
data['mobile'] = mobile
if 'street' in fields and not data.get('street'):
data['street'] = branch
if 'email_from' in fields and not data.get('email_from'):
data['email_from'] = email
if 'x_date' in fields and not data.get('x_date'):
data['x_date'] = date
res_id = model_pool.create(cr, uid, data, context=context)
return res_id
This is your condition
if 'Caller\nEmail:' in newstring:
if newstring.index('Caller\nEmail:'):
indx4=newstring.index('Caller\nEmail:')
emailstr=newstring[indx4+1]
emailarr=emailstr.split("[")
email=emailarr[0]
else:
email = ''
else:
email = ''

Want to make sure object not in queryset before adding it

My "Event" object has a "Name" field. There is the possibility that the name is wrong, so a user may suggest a new name. That name gets put into the event's "suggestedN" list. However, I don't want there to be duplicates of one suggestion in that list. I felt like this was a straightforward problem, but for some reason am not finding much success.
Here is how my view currently looks:
#login_required
def suggestName(request):
name = request.POST['name'].strip()
event_id = request.POST['event_id']
try:
e = Event.objects.get(event_id = event_id)
except Event.DoesNotExist:
e = customEvent.objects.get(event_id = event_id)
if name in e.suggestedN.all():
pass
else:
(some code)
Is my if name in e.suggestedN.all() statement wrong?
Here's a brief view of my Event's model:
class Event(models.Model):
def __unicode__(self):
return self.title
suggestedN = models.ManyToManyField('suggestedName', blank = 'TRUE', null = 'TRUE')
class suggestedName(models.Model):
def __unicode__(self):
return self.name
name = models.CharField(max_length=200, blank = 'TRUE', null = 'TRUE')
votes = models.IntegerField(default = 0)
You should use the name attribute on m2m not the m2m itself to compare
#login_required
def suggestName(request):
name = request.POST['name'].strip()
event_id = request.POST['event_id']
try:
e = Event.objects.get(event_id = event_id)
except Event.DoesNotExist:
e = customEvent.objects.get(event_id = event_id)
if name in e.suggestedN.values_list('name', flat=True):
pass
else:
(some code)

Many to one relation not working in fields.selection() in openerp

I need to create a selection field in openerp , it's values should load from a function and also this field needs many2one relation with another table.I have created the selection field and values are loaded from the function but many2one relation not working in it.below given is my code.
def _sel_proj(self, cr, uid, context=None):
cr.execute("""SELECT project.id,account.name 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)
GROUP BY project.id,account.name"""%(uid, uid))
return [(r[0],r[1]) for r in cr.fetchall()]
_name = 'mat.mgmt'
_columns = {'project_id':fields.selection(_sel_proj,string='Project',type="many2one",relation="project.project",select="true",required="true"),}
change the field project_id to many2one and in the view for the field add widget='selection'.
in python:
_columns = {'project_id':fields.many2one('project.project','Project',select="true",required="true"),}
in xml:
<field name="project_id" widget="selection"/>
then override the fields_view_get function and add the filter condition for project_id. For example
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
if context is None:context = {}
res = super(<your_class_name>,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
for field in res['fields']:
if field == 'project_id':
cr.execute("""SELECT project.id,account.name 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)
GROUP BY project.id,account.name"""%(uid, uid))
project_select = [(r[0],r[1]) for r in cr.fetchall()]
res['fields'][field]['selection'] = project_select
return res