I am trying to dynamically change the values of a many2many field products_ids based on multiple onchange functions of other fields (e.g. brand_id and origin_id).
So far everything is working great and it does show the expected values, but once i hit the save button the values of the many2many field disappear
class CustomModifyPrice(models.Model):
brand_id = fields.Many2many(comodel_name="custom.brand", string="Brand", required=False, )
origin_id = fields.Many2many(comodel_name="custom.country", string="Origin", required=False, )
product_ids = fields.Many2many(comodel_name="custom.product", string="Products", readonly=True, )
search_terms = {}
product_ids_list = []
#api.onchange('brand_id')
def onchange_change_brand(self):
for rec in self:
product_brands = []
for prod_brand in rec.brand_id:
product_brands.append(prod_brand.id)
rec.search_terms["product_brands"] = product_brands
rec.get_products()
#api.onchange('origin_id')
def onchange_change_origin(self):
for rec in self:
product_origins = []
for prod_origin in rec.origin_id:
product_origins.append(prod_origin.id)
rec.search_terms["product_origins"] = product_origins
rec.get_products()
def get_products(self):
domain = []
self.product_ids_list = []
if 'product_brands' in self.search_terms:
product_brands = self.search_terms['product_brands']
if product_brands:
tuple1 = ('brand_id', 'in', product_brands)
domain.append(tuple1)
if 'product_origins' in self.search_terms:
product_origins = self.search_terms['product_origins']
if product_origins:
tuple1 = ('country_id', 'in', product_origins)
domain.append(tuple1)
if domain:
products = self.env['custom.product'].search(domain)
if products.ids:
for prod in products:
self.product_ids_list.append(prod.id)
self.product_ids = [(6, False, self.product_ids_list)]
Make sure force_save="1" is placed as an attribute in your field (xml file)
Related
i am stuck since a couple of days in some many2many and one2many field i am trying to add value to through code. The idea is to consume a web service to get some data from a third party website and re-use these same data in my odoo 12 modules. I was able to parse the JSON request and create entities using model.Models. However, for fields using one2many or many2many i was unable to add their values and link them to my models. Here is my python code. What i want to achieve is after the creation of a record "book.db" i want to also create its category in the same time and link it to the current record. However everytime i run the code only the "book.db" model is created. The category model is never made nor linked. Can someone point me to the right direction or correct my code if possible. Thanks alot.
from odoo import models, fields, api
from . import prestashopproduct
import requests
import json
class Book(models.Model):
_name = "book.db"
prestashop_id = fields.Integer('Prestashop ID')
title = fields.Char(string="book title")
ean13_code = fields.Char(string="EAN13")
author = fields.Char(string="book author")
released = fields.Date(string="Date de publication")
type = fields.Selection([('Numérique', 'Numérique'), ('Papier', 'Papier')], string="type")
catalog = fields.Char(string="catalogue")
collection = fields.Char(string="collection")
isbn = fields.Char(string="Numero ISBN")
description = fields.Html("Description")
distributeur = fields.Char(string="Distribiteur")
code_distribiture = fields.Char(string="Code distribiteur")
code_collection = fields.Char(string="Code collection")
code_dispo = fields.Char(string="Code dispo")
code_tva1 = fields.Integer("Code tva1")
code_tva2 = fields.Integer("Code tva2")
presentation = fields.Html("Presentation")
type_produit = fields.Char(string="Type de produit")
theme_edilectre = fields.Char(string="Type de produit")
categorie = fields.Html("categorie")
poid = fields.Float("Poid en Gramme")
prix = fields.Float("Prix")
largeur = fields.Float("Largeur en MM")
epaisseur = fields.Float("Epaisseur en MM")
hauteur = fields.Float("Hauteur en MM")
image = fields.One2many('product.images', 'product_id', string='Imags du produit')
cate = fields.Many2many('product.cetegorie', 'product_id', string='Imags du produit')
image_product = fields.Char("Image")
#api.one
def get_books(self):
jso = prestashopproduct.Product.get_full_stock(self=prestashopproduct.Product())
for j in jso['products']:
if self.check_unicity(j['id']):
book = [{'title': j['name'][1]['value'],
'ean13_code': j['ean13'],
'isbn': j['isbn'],
'epaisseur': j['width'],
'largeur': j['depth'],
'hauteur': j['height'],
'poid': j['weight'],
'prestashop_id': j['id'],
'description': j['description'][1]['value'],
'presentation': j['description_short'][1]['value'],
'categorie': j['description_short'][1]['value']}]
record = self.create(book)
print (self.id)
record.cate.create({'cate': [{'product_id': record.id, 'name': 'absc'}]})
def check_unicity(self, id):
if self.search_count([('prestashop_id', '=', id)]) > 0:
return False
else:
return True
class Image(models.Model):
_name = 'product.images'
product_id = fields.Many2many('book.db', string='Prestashop ID')
product_image = fields.Binary('Image du produit')
product_image_url = fields.Char("product_image")
def donload_product_image(self, product_id, image_id):
image = prestashopproduct.Product.get_product_image(prestashopproduct.Product(), id_product=product_id,
id_image=image_id)
return image
class Categories(models.Model):
_name = 'product.cetegorie'
product_id = fields.Many2many('book.db', string="Categories")
nb_products_recursive = fields.Integer("nb_products_recursive")
name = fields.Char("Descriptif")
#api.one
def new_record(self, product_id):
self.create([{'product_id': product_id, 'name': 'a'}])
#api.model
def _repare_cate_list(self, cates=[]):
post_cates = []
existing_add = []
for cate_name in cates:
cate_ids = self.env['product.cetegorie'].search([('name', '=', cate_name)])
if cate_ids:
existing_add.append(int(cate_ids[0]))
else:
post_cates.append((0, 0, {'name': cate_name}))
post_cates.insert(0, [6, 0, existing_add])
return post_cates
#api.one
def get_books(self):
jso = prestashopproduct.Product.get_full_stock(self=prestashopproduct.Product())
for j in jso['products']:
if self.check_unicity(j['id']):
cate_vals = self._repare_cate_list(['absc'])
book = [{'title': j['name'][1]['value'],
'ean13_code': j['ean13'],
'isbn': j['isbn'],
'epaisseur': j['width'],
'largeur': j['depth'],
'hauteur': j['height'],
'poid': j['weight'],
'prestashop_id': j['id'],
'description': j['description'][1]['value'],
'presentation': j['description_short'][1]['value'],
'categorie': j['description_short'][1]['value'],
'cate':cate_vals
}]
record = self.create(book)
Also remove line product_id = fields.Many2many('book.db', string="Categories") from the 'product.cetegorie' model its not needed. As Many to many is using separate table to link categories to save them.
Whenever you want to edit, update or delete One2many or Many2many field(s) please refer below lines.
(0, 0, {values}) link to a new record that needs to be created with
the given values dictionary
(1, ID, {values}) update the linked record with id = ID (write values
on it)
(2, ID) remove and delete the linked record with id = ID (calls unlink
on ID, that will delete the object completely, and the link to it as
well)
(3, ID) cut the link to the linked record with id = ID (delete the
relationship between the two objects but does not delete the target
object itself)
(4, ID) link to existing record with id = ID (adds a relationship)
(5) unlink all (like using (3, ID) for all linked records)
(6, 0, [IDs]) replace the list of linked IDs (like using (5) then (4,
ID) for each ID in the list of IDs)
I'm building an API that will require the cleaning of input data into a modelform m2m field before creating the model instance.
The data will come in as a string of names, I will need to clean the data and add link the m2m relationship manually.
What is the proper way to link these relationships within the manytomany field during the clean Def. Do I simply append each into the field itself?
Below is my working "clean" def:
def clean_sourcingbroker(self):
broker = self.cleaned_data['broker']
cleanlist = []
names = []
for name in broker.replace(', ', ',').split(' '):
name = name.split(',')
last_name = name[0]
first_name = name[1]
names.append((last_name, first_name))
for name in names:
brokerobj = Broker.objects.get(lastname=name[0], firstname=name[1])
cleanlist.append(brokerobj)
return cleanlist
# If you want to change the value of a field, then you can use
def to_internal_value(self, data):
validatedData = (super(SerializerClass, self).to_internal_value(data))
broker = validatedData["broker"]
cleanlist = []
names = []
for name in broker.replace(', ', ',').split(' '):
name = name.split(',')
last_name = name[0]
first_name = name[1]
names.append((last_name, first_name))
for name in names:
brokerobj = Broker.objects.get(lastname=name[0], firstname=name[1])
cleanlist.append(brokerobj)
validatedData["broker"] = cleanlist
return validatedData
# If you want to validate the field, then you can use
def validate(self, data):
if len(data['broker']) == 0:
raise serializers.ValidationError("validation error for broker field")
return data
i need to make a computed method to calculate the range of years on fire while importing excel sheet
if it onChange without dependence api it work well when i but manually records into fields but also not work while importing data
i trired this code but when i'am importing data or inter record into fields i get an error as a title and below
class relate(models.Model):
_name = 'relate'
_rec_name = 'car'
#api.multi
#api.depends('start', 'end', 'ignore')
def years_rang(self):
for rec in self:
if rec.start and rec.end:
record = [int(x) for x in range(int(rec.start), int(rec.end) + 1)]
list = []
if rec.ignore:
try:
record.remove(int(self.ignore))
list = []
except ValueError:
return {'warning': {'title': 'Warning!', 'message': "the Ignored year doesn't in range"}}
for item in record:
range_id = self.env['yearrange'].create({'name': str(item)})
list.append(range_id.id)
rec.rang = [(4, x, None) for x in list]
pass
start = fields.Char(string="", required=False, )
end = fields.Char(string="", required=False, )
rang = fields.One2many(comodel_name="yearrange", inverse_name="product_id", store=True, string="Years" ,compute="years_rang")
ignore = fields.Char(string="Ignore", required=False, )
class yearrange(models.Model):
_name = 'yearrange'
_rec_name = 'name'
name = fields.Char()
product_id = fields.Many2one(comodel_name="relate")
maximum recursion depth exceeded while calling a Python object
I have a form which is collecting data about a variable to be created. I want to create a list of variables which are already there in the database. I am doing this by creating a ManyToMany relationship. When I start the server, the list of variables gets saved on the application, but it does not alter the database field named selective list.
forms.py
class VariableForm(ModelForm):
class Meta:
model = variable
fields = ['name', 'area', 'parameterName', 'order', 'type', 'format', 'units', 'comboItems',
'hiAlarm', 'loAlarm', 'scaleHiMax', 'scaleLoMax', 'deviationAlarm','selectiveList', 'round',
'days', 'required', 'hidden', 'readOnly', 'holdLast', 'calibrationFrequency',
'dateNextCalibration', 'triggerCalibrated']
widgets = {
'comboItems': forms.Textarea(attrs={'rows':1, 'cols': 40, 'style': 'height: 2em;padding-top:0'}),
'forceValue': forms.Textarea(attrs={'rows':1, 'cols': 40, 'style': 'height: 2em;padding-top:0',
'placeholder':'This will force all input to this variable'})
}
#selectiveList = forms.ModelMultipleChoiceField(queryset=variable.objects.all().order_by('-name').reverse())
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(VariableForm, self).__init__(*args, **kwargs)
self.fields['round'] = forms.ModelMultipleChoiceField(
queryset=opRound.objects.all(),
widget=forms.SelectMultiple,
label='Rounds',
required=False
)
self.fields['selectiveList'] = forms.ModelMultipleChoiceField(
queryset=variable.objects.all().order_by('-name').reverse(),
widget=forms.SelectMultiple,
label='Select Variables',
required=False
)
self.fields['days'] = forms.ModelMultipleChoiceField(
queryset=dayOfWeek.objects.all(),
widget=forms.SelectMultiple,
label='Days',
required=False
)
self.fields['area'].choices = AreaIterator(request = self.request)
try:
self.fields['order'].initial = variable.objects.latest().order+1
except Exception,e:
print e
model.py
class variable(models.Model):
name = models.CharField(max_length=255)
area = models.ForeignKey(area)#parent
order = models.IntegerField("Order Index (0 is first, 1 is next, etc.)",default=999)#order index to display in order correctly, ascending
type = models.CharField(max_length=255, choices=(("Value", "Value"), ("Runtime", "Runtime/FlowTotal"),
("Message", "Message"), ("CheckBox", "Check Box List"), ("Selection", "Selection Box"), ("Formula2", "Formula with other Variables"),
("OnOff", "In/Out of Service Selection"), ("OnOffSelection", "Selective On/Off")),
default = "Value" )#what type of variable
format = models.CharField(max_length=255,choices=(("Number", "Number (Without Decimals)"),
("2Number", "Number (With Decimals)"), ("Date", "Date"),
("Time", "Time"), ("Text", "Text")), blank=True, null=True, default="2Number" )#number format if needed
units = models.CharField(max_length=255,blank=True,null=True)#units of measurement
required = models.BooleanField(default=True)#is the variable required in a round
hiAlarm = models.FloatField("High Alarm",blank=True,null=True)#red notify if above
loAlarm = models.FloatField("Low Alarm",blank=True,null=True)#yellow notify if below
scaleHiMax = models.FloatField("Limit maximum value",blank=True,null=True)#scale to high max if needed
scaleLoMax = models.FloatField("Limit low value",blank=True,null=True)#scale to low if needed
deviationAlarm = models.FloatField("Deviation Alarm",blank=True,null=True,
help_text="Triggers an alarm if the value between this record and the last is greater than this percentage.")#%change check
round = models.ManyToManyField(opRound,blank=True)#round of gathering data
days = models.ManyToManyField(dayOfWeek,blank=True)#day of the week
selectiveList = models.ManyToManyField("self",through="variable",blank=True,symmetrical=False)#List to determine which variables to display when the selection is "OFF"
parameterName = models.CharField("Parameter Name (ReportID)",max_length=255,blank=True,null=True)#hachWIM ID
comboItems = models.TextField("List of comma separated options.", blank=True,null=True)#list deliminated by a column for choosing
#PUT EQUATION HERE
hidden = models.BooleanField("Sync to tablet",default=True)#this muse be True if required is true
readOnly = models.BooleanField("Read only.", default = False)
dateTimeEdited = models.DateTimeField(auto_now=True)#date edited
userEdited = models.ForeignKey(CustomUser,blank=True,null=True,related_name="userEditedV")# last user to edit data
forceValue = models.TextField(blank=True,null=True)#force reading
userForced = models.ForeignKey(CustomUser,blank=True,null=True,related_name="userForcedV")# last user to force data
useForce = models.BooleanField("Turn Forcing On", default=False)
dateNextCalibration = models.DateField("Next Calibration Date", blank=True,null=True, help_text="YYYY-MM-DD")
triggerCalibrated = models.BooleanField("Trigger next calibration date", default=False)
calibrationFrequency = models.ForeignKey(calibrationFrequency, blank=True, null=True)
version = models.BigIntegerField(default=1)#used for sync
holdLast = models.BooleanField("Selecting this will hold the last value on the tablet automatically.", default=False)
When we are trying to do it from different models, such as round or days, it creates a new database table with those relations. I want to store the selected values as a string list in the selective list column in the same model.
Here is what the multiple select looks like.
I'd like to return a result object which contains the indexed document AND other information, from another entity, with which the indexed document has a relationship.
So, let's say I have two Kinds:
class Store(BaseHandler):
store_name = ndb.StringProperty()
logo_url = ndb.StringProperty()
about_store = ndb.TextProperty()
class Product(BaseHandler):
product_name = ndb.StringProperty
store_key = ndb.KeyProperty() #Store entity which created this product.
Then, I add each new Product entity to the index, like this:
class NewProduct(BaseHandler):
def get(self, store_id):
self.render('new-product.html')
def post(self, store_id):
product_name = self.request.get('product_name')
store_key = ndb.Key('Store', store_id)
try:
p = Product(
store_key = store_key,
product_name = product_name)
p.put()
# Add p to index
p_doc = search.Document(
doc_id = str(p.key.id()),
fields = [
search.AtomField(name = 'store_id', value = str(str_id)),
search.TextField(name = 'product_name', value = e.product_name)])
index = search.Index('product_index')
index.put(p_doc)
except:
# handle error
Now, if I run a search query using...
index = search.Index('product_index')
index.search('PRODUCT_NAME')
I should be able to return all the Product documents from the index by its query string.
My question is: How do I efficiently return a result object which contains both the product document AND its Store kind information (store_name, logo_url, about_store)?