How do I get values from a one2many field? - python

I have three models which are connected with each other.
The first one is an inheriting of product.template (product_template.py) and as you see I have a one2many field which is connected to the second model showed in here.
When I want to access variables from product_template.py with dot notation I can see variable suggestion and I guess it works fine.
class ProductTemplate(models.Model):
_inherit = "product.template"
kestet_ids = fields.One2many('kestet.lines', 'product_template_id', string="Kestet", store=True)
class OnetoMany(models.Model):
_name = "kestet.lines"
partner_id = fields.Many2one("res.partner")
kestet = fields.Char(string="Emri i Kestit(n)")
vlera = fields.Integer(string="Vlera e Kestit(n)")
data = fields.Date()
sel1 = fields.Selection(
[('kontrate', 'Kontrate'), ('levrim', 'Levrim Kredie'), ('karabina', 'Karabina'), ('hipoteka', 'Hipoteka'),
('Celsat', 'Celsat'), ('Ne Perfundim', 'Ne Perfundim'),
('other', 'Tjeter')], string="Menyra Likujdimit")
pagesa1 = fields.Selection([('Cash', 'Cash'), ('Bank', 'Bank'), ('Klering', 'Klering')], string="Menyra Pageses")
product_template_id = fields.Many2one("product.template")
property_contract_id = fields.Many2one("property.contract")
Now when I try to access it from this other model property_contract.py and do the same thing as above, it doesn't give me variable suggestions and I can not access variable values.
class PropertyContract(models.Model):
_name = "property.contract"
_order = 'start_date'
name = fields.Char("Contract Number")
kestet2_ids = fields.Many2one('kestet.lines')
I also tried:
installment_id = fields.Many2one("product.templates")
installment_relation = fields.One2many(related="installment_id.kestet_ids")
It failed giving me results. I tried also the above code but didn't work...
What am I doing wrong here?

Related

odoo14 on change only gets called on specific change

This is the on change function of one of my models in my odoo14 module:
#api.onchange('staende', 'name', 'length', 'height')
def change(self):
print("\033[92m +++ DEBUG#ONCHANGE +++")
print(self)
print("\033[93m", end="")
weirdly enough, the method only gets called when I change the name of the model but not when I change the length or height nor the staende attribute
this is what the model looks like:
class Halle(models.Model):
_name = 'rectanglemaps.halle'
_inherit = 'mail.thread'
_description = 'desc'
active = fields.Boolean('Active', default=True)
name = fields.Char(string="Name", required=True)
length = fields.Float(string="Länge", required=True)
height = fields.Float(string="Tiefe", required=True)
measurehalle = fields.Float(string="Rastermaß")
plan = fields.Image(string="Plan")
messe_id = fields.Many2one('rectanglemaps.messe', string="Messe")
staende = fields.One2many('rectanglemaps.stand', 'halle_id', string="Stände")
It appears, it was only a problem with hot module reloading. Restarting odoo with the flag -u MODULENAME solved the problem.

Odoo 12 how to display model records in one field, depending on the model chosen in other field

After several hours and differente approaches, can't reach to get what I need.
I'm developing a module to configure different kind of properties in a product.category, once a product is assigned a categ_id, I copy all the properties of this category to this product, for the user to assign the value of everyone.
Is pretty simple, model product.category.properties
class ProductCategoryProperties(models.Model):
_name = 'product.category.properties'
_order = "category_id, name"
#CONFIG. OPTIONS
VALUE_TYPES = [('char', 'Texto corto'), ('text', 'Texto largo'), ('num', 'Número'), ('oper', 'Operación'), ('list', 'Lista')]
OPERATION_TYPES = [('sum','Suma'),('sub','Resta'),('mul','Multiplicación'),('div','División')]
#FIELDS
category_id = fields.Many2one('product.category', string='Categoría', required=True, ondelete='cascade', index=True, copy=False)
name = fields.Char(string='Nombre', translate=True, required=True)
description = fields.Text(string='Descripción', translate=True)
value_type = fields.Selection(selection=VALUE_TYPES, default='char', string='Tipo valor', size=64, help='Tipo de valor de la propiedad', required=True)
value_min = fields.Float(string="Mínimo", help="Valor mínimo permitido")
value_max = fields.Float(string="Máximo", help="Valor máximo permitido")
operation_type = fields.Selection(selection=OPERATION_TYPES, default='sum', string='Tipo operación', size=64, help='Tipo de operación de la propiedad')
operation_field1 = fields.Many2one('product.category.properties', string='Campo 1', ondelete='cascade')
operation_field2 = fields.Many2one('product.category.properties', string='Campo 2', ondelete='cascade')
model_id = fields.Many2one('ir.model', string="Lista", ondelete='cascade')
Model product.properties (properties copied from product.category.properties when product.categ_id is filled.
class ProductProperties(models.Model):
_name = 'product.properties'
_order = "product_id, product_category_property_id"
#FIELDS
product_id = fields.Many2one('product.template', string='Producto', required=True, ondelete='cascade', index=True, copy=False)
product_category_property_id = fields.Many2one('product.category.properties', string='Propiedad', required=True, ondelete='cascade', index=True, copy=False)
value = fields.Char(string='Valor')
value_record = fields.Selection(string='Valor registro', selection='get_model_values', size=64)
value_wizard = fields.Integer(string='Valor wizard')
hide_record = fields.Boolean(string='Ocultar', compute='_hide_record', store=True)
#FUNCTIONS
def get_model_values(self):
#vals = [('1','Uno'), ('2','Dos')]
vals3 = []
res_partner = self.env['res.partner'].search([])
for i in res_partner: vals3.append([i.id, i.name])
uom_uom = self.env['uom.uom'].search([])
for j in uom_uom: vals3.append([j.id, j.name])
return vals3
As you can see that's easy, there are other functions to validate that values are between Min and Max values, and to calculate operations, for example Superficie (50) = Ancho (5) * Largo (10).
The problem comes when I need field "Valor" of "Lista" to display model records depending on the model chosen ("Lista".model_id), in this case Contacto (res.partner) but could be anyone.
I have tried with:
- different field types (value, value_record, value_wizard)
- tried some function like "def get_model_values", but needs to have the model hardcoded and doesn't really work to show different model records, for example res.partner for one record (Lista) and other model for other record (Lista2)
- heard about displaying a wizard to show records of a different model every time and return the id or other field of the selected record, but don't know how
- heard about using javascript/jquery to replace values directly on front, but don't know how
I have seen too that mail.message has a res_id integer field, that stores id of different record models. Model could be solved this way, but the problem is that I need to display record lists for the user to choose.
Anyone that could help would be appreciated.
Thanks!

Django Can't save record with ForeinKey

I am familiar with the Django and I am using Django framework(2.2.2) in one of my website, But I am getting one weird issue for saving record with the foreign key:
I have following two models
class quick_note(models.Model):
note_id = models.AutoField(primary_key=True)
meeting_date = models.DateField(max_length=55)
title = models.TextField(blank = True,null=True)
headline = models.TextField(blank = True,null=True)
class quick_note_details(models.Model):
meeting_id = models.ForeignKey(quick_note,on_delete = models.CASCADE)
summary = models.TextField(default='',null=True)
Following is the code I have used for saving:
quick_note_details_data = quick_note_details(summary = summary_data,meeting_id = 1)
quick_note_details_data.save()
Using this I am getting following error:
ValueError: Cannot assign "2": "quick_note_details.meeting_id" must be a "quick_note" instance.
Then, I have tried the following approach suggested in the following question,
Django: ValueError when saving an instance to a ForeignKey Field
quick_note_obj = quick_note.objects.get(note_id = note_id)
quick_note_details_data = quick_note_details(summary = summary_data,meeting_id = quick_note_obj)
quick_note_details_data.save()
Using this I am getting following error:
django.db.utils.ProgrammingError: column "meeting_id_id" of relation "website_quick_note_details" does not exist
LINE 1: INSERT INTO "website_quick_note_details" ("meeting_id_id", "...
I don't have a column like meeting_id_id in the model anywhere, then why I am getting this error?
I have been searching for this long time, but didn't get any solution,
Hope I will get help here.
change meeting_id to meeting_id_id , try following
quick_note_details_data = quick_note_details(summary = summary_data,meeting_id_id = 1)
So, I had got my answer days back, so decided to answer so this will help people like me,
Basically, Django appends a suffix to the foreign_key columns,
e.g if your columns name is note ,Django will assume this as note_id,
So,To avoid this I had done only the following:
note_id = models.ForeignKey(quick_note,on_delete = models.CASCADE,db_column='note_id')
By using db_column property, now the foreign key will refer as note_id,
This solves my issue.

Odoo: How to create many records in Transient.Model?

This code only creates one record. What is wrong?
class PartnerTagCreate(models.TransientModel):
""" Choose tags to be added to partner."""
_name = 'partner.tags.create'
_description = __doc__
market_id = fields.Many2one('partner.tags', string='Market Tag')
application_id = fields.Many2one('partner.tags', string='Application Tag')
partner_id = fields.Integer()
#api.multi
def create_contact_tag(self):
for record in self.env['sale.order.line'].browse(self._context.get('active_ids', [])):
vals = {}
vals['partner_id'] = record.order_partner_id
self.write(vals)
return True
I need this function to create one record for each order_partner_id I selected before opening the wizard...
How to achieve that?
Here my new code (function) ...
def create_contact_tag(self):
sale_order_line_ids = self.env['sale.order.line'].browse(self._context.get('active_ids', []))
for partner in sale_order_line_ids:
values = {}
values['partner_id'] = partner.order_partner_id
self.create(values)
return {}
This creates one record for marketing_id and/or application_id and dedicated records for each partner_id in the record.
You use the 'create' method to create new records; this is the same for TransientModel as for the persistent Model.
So, replace
self.write(vals)
by
self.create(vals)
and you should be fine.

Associate classes with django-filters

Bonjour, I have a question regarding django-filters. My problem is:
I have two classes defined in my models.py that are:
class Volcano(models.Model):
vd_id = models.AutoField("ID, Volcano Identifier (Index)",
primary_key=True)
[...]
class VolcanoInformation(models.Model):
# Primary key
vd_inf_id = models.AutoField("ID, volcano information identifier (index)",
primary_key=True)
# Other attributes
vd_inf_numcal = models.IntegerField("Number of calderas")
[...]
# Foreign key(s)
vd_id = models.ForeignKey(Volcano, null=True, related_name='vd_inf_vd_id',
on_delete=models.CASCADE)
The two of them are linked throught the vd_id attribute.
I want to develop a search tool that allows the user to search a volcano by its number of calderas (vd_inf_numcal).
I am using django-filters and for now here's my filters.py:
from .models import *
import django_filters
class VolcanoFilter(django_filters.FilterSet):
vd_name = django_filters.ModelChoiceFilter(
queryset=Volcano.objects.values_list('vd_name', flat=True),
widget=forms.Select, label='Volcano name',
to_field_name='vd_name',
)
vd_inf_numcal = django_filters.ModelChoiceFilter(
queryset=VolcanoInformation.objects.values_list('vd_inf_numcal', flat=True),
widget=forms.Select, label='Number of calderas',
)
class Meta:
model = Volcano
fields = ['vd_name', 'vd_inf_numcal']
My views.py is:
def search(request):
feature_list = Volcano.objects.all()
feature_filter = VolcanoFilter(request.GET, queryset = feature_list)
return render(request, 'app/search_list.html', {'filter' : feature_filter, 'feature_type': feature_type})
In my application, a dropdown list of the possible number of calderas appears but the search returns no result which is normal because there is no relation between VolcanoInformation.vd_inf_numcal, VolcanoInformation.vd_id and Volcano.vd_id.
It even says "Select a valid choice. That choice is not one of the available choices."
My question is how could I make this link using django_filters ?
I guess I should write some method within the class but I have absolutely no idea on how to do it.
If anyone had the answer, I would be more than thankful !
In general, you need to answer two questions:
What field are we querying against & what query/lookup expressions need to be generated.
What kinds of values should we be filtering with.
These answers are essentially the left hand and right hand side of your .filter() call.
In this case, you're filtering across the reverse side of the Volcano-Volcano Information relationship (vd_inf_vd_id), against the number of calderas (vd_inf_numcal) for a Volcano. Additionally, you want an exact match.
For the values, you'll need a set of choices containing integers.
AllValuesFilter will look at the DB column and generate the choices from the column values. However, the downside is that the choices will not include any missing values, which look weird when rendered. You could either adapt this field, or use a plain ChoiceFilter, generating the values yourself.
def num_calderas_choices():
# Get the maximum number of calderas
max_count = VolcanoInformation.objects.aggregate(result=Max('vd_inf_numcal'))['result']
# Generate a list of two-tuples for the select dropdown, from 0 to max_count
# e.g, [(0, 0), (1, 1), (2, 2), ...]
return zip(range(max_count), range(max_count))
class VolcanoFilter(django_filters.FilterSet):
name = ...
num_calderas = django_filters.ChoiceFilter(
# related field traversal (note the connecting '__')
field_name='vd_inf_vd_id__vd_inf_numcal',
label='Number of calderas',
choices=num_calderas_choices
)
class Meta:
model = Volcano
fields = ['name', 'num_calderas']
Note that I haven't tested the above code myself, but it should be close enough to get you started.
Thanks a lot ! That's exactly what I was looking for ! I didn't understand how the .filter() works.
What I did, for other attributes is to generate the choices but in a different way. For instance if I just wanted to display a list of the available locations I would use:
# Location attribute
loc = VolcanoInformation.objects.values_list('vd_inf_loc', flat=True)
vd_inf_loc = django_filters.ChoiceFilter(
field_name='vd_inf_vd_id__vd_inf_loc',
label='Geographic location',
choices=zip(loc, loc),
)

Categories