Why related fields use Write function - odoo

_name = "my.table"
building_id = fields.Many2one('building', related='floor_id.building_id', readonly=False)
floor_id = fields.Many2one('building.floor')
A user with the read access to 'building' and 'building.floor' tables, tries to create a record in "my.table" If the user chooses building_id and floor_id together an error occurs. The error says that my user has no access to write 'building.floor' table. My question is: why a related field use the write function, what is the difference between the compute and related in this scenario?

Related fields are very simple computed fields. So simple they can be "implemented" with one parameter on field definition. Odoo has generic methods for those fields. For example a lot of developers don't write inverse methods for computed fields, which inverse the compute method, because the simply don't need it. But without it and without storing the computed field, Odoo sets the field readonly.
Related fields have a generic inverse method. In your case changing building_id when there was already a floor_id chosen, Odoo will write the building_id on that floor_id.building_id, because that's how related fields work (i know that's not the best explanation).
The user obviously has no write/update rights on builiding.floor model and that's why there will be the access error message in the end, because Odoo wants to write the new building on the floor.
Seems to me you want to filter the floors by buildings, but you shouldn't use a related field for that. Just put a domain on floor_id which filters by the chosen building_id:
floor_id = fields.Many2one('building.floor', domain="[('building_id', '=?', building_id)]")
You could also use domain operator =, but =? will show all floors when no building was set yet.

Related

Odoo 15 Find tax_ids Inside the account.move.line (Invoice) Model

Good day, hope everything's well.
I'm trying to find the value of tax_ids (Many2many field) inside the account.move.line model but i can't seems to find anything. I already access the psql of the database but i cant find tax_ids too.
I accessed that account.move.line model with ORM like this :
def _post(self, soft=True):
for move in self:
....
account_move_line = self.env['account.move.line'].search([('id', '=', int(move.id))])
print(account_move_line.tax_ids) #this find nothing
could someone please elaborate how is it possible to access id of the tax that applied to, in this case, an invoice line record?
Edit : Sometimes this ORM fetching the ID and sometimes it doesn't. But most likely it's not fetching.
I'm trying to find the value of tax_ids (Many2many field) inside the
account.move.line model but i can't seems to find anything. I already
access the psql of the database but i cant find tax_ids too.
tax_ids in account.move.line model is a Many2Many field, which is stored separately as another table in the database. This kind of relation field mostly be named something like this (main_table)_(related_table)_rel (ignore the parentheses). For example, this particular case's table is account_move_line_account_tax_rel since its main table is account_move_line and the related table for that specific field is account_tax. Inside the relation table, you will almost always find 2 fields mapping both ids together. For this case, it is going to be account_move_line_id and account_tax_id.
I accessed that account.move.line model with ORM like this :
def _post(self, soft=True):
for move in self:
....
account_move_line = self.env['account.move.line'].search([('id', '=', int(move.id))])
print(account_move_line.tax_ids) #this find nothing could someone please elaborate how is it possible to access id of the tax
that applied to, in this case, an invoice line record?
Edit : Sometimes this ORM fetching the ID and sometimes it doesn't.
But most likely it's not fetching.
Accessing a field via ORM always works as you intended if it is implemented correctly. In your code, you are searching account_move_line by id but you are trying to search it with move.id, which I assume it is account_move since you got the data sometimes. If you can access the lines that you want correctly, you will see that account_move_line.tax_ids will always give you the correct tax_ids. From what your code looks, I think you are trying to search the lines by its account_move. Therefore, your domain should be [('move_id', '=', int(move.id))] instead.

Compute many2many field with values from another model using Odoo developer interface

I need a new field inside Contact model that would hold information about Allowed companies of the related user.
Now there is only field about Currently picked company by that user (and it is not enough for me to make a record rule).
The field I want to copy values from is inside model Users and it is called company_ids.
I’m trying to add this field in the developer mode (Settings > Technical > Fields) like this:
But I’m having trouble with code that would fill my field with values from the another model.
for record in self:
record[("x_company_ids")] = env['res.users'].company_ids
I’m guessing that the record is referring to a record inside Contact model and it does not contain fields from another models like Users. So I can’t figure it out how to reference a field from another model.
Something similar to this: env['res.users'].company_ids?
It is even harder for me because it is many2many field and should always update when the source changes.
Maybe better solution would be to use Automatic action to write values to this field?
I saw some threads like this: Computed many2many field dependencies in Odoo 10.
But it seems like in those cases they had clear connection between the fields and I don't have it. I don't know how to get related user while I'm inside Contact model. I know only how to this oposite way (from user to contact): user.partner_id.id
Here in below given code you haven't specified related user from which you will get company_ids, you have directly accessing company_ids
for record in self:
record[("x_company_ids")] = env['res.users'].company_ids
You can write as following :
for record in self:
record["x_company_ids"] = self.env['res.users'].search([('partner_id','=',record.id)]).company_ids

How to create a temp boolean field with Django orm

Image I have following models:
class Product(models.Model):
name = models.CharField(max_length=20)
class Receipt(models.Model):
product = models.ForeignKey(Product)
user = models.ForeignKey(User)
I have an input list of product ids and a user. I want to query for each product, whether it's been purchased by this user. Notice I need a queryset with all exist products based on given input because there are other fields I need for each product even not purchased by this user, so I cannot use Product.objects.filter(receipt__user=user).
So can I create a temp Boolean field to present this property in one single query? I am using Django 1.8 and postgresql 9.3
Update requirements:To separate products into two groups. One is bought by this specific user, the other one is not. I don't think any given filter can implement this. This should be implement by creating a new temp field either by annotate or F expression.
I think, you need .annotate() expression as
from django.db.models.expressions import Case, When, Value
product_queryset = Product.objects.annotate(
is_purchased=Case(
When(receipt__user=current_user, then=Value('True')),
default=Value('False')
))
How to access the annotated field?
product_queryset.first().is_purchased
Thx for #JPG's answer.
I just realize except conditional expressions, there's another easy way to do it.
Just using prefetch_related will implement everything in two queries. Although it's double than conditional expressions, but it's still a considerable time complexity solution.
products = Product.objects.filter(id__in=[1,2,3,4,5]).prefetch_related ('receipt_set').all()
Then we can detect user for this product in Python by
for p in products:
print user in [receipt.user_id for receipt in p.purchase_set.all()]

concept of create method odoo8

I'm new at using odoo, so i faced an override of create method but still don't quite understand the concept.
This is the create method I used :
#api.model
def create(self, vals):
vals['task_idd'] = self.env['crane.task'].create({'equipment_id': vals['equipment_id'], 'type': vals['type']}).id
vals['task_ids'] = [(4, vals['task_idd'])]
return super(crane_workorder, self).create(vals)
this code works perfectly
i had a one2many relation that has been converted into one2one(logically), so i override the create method till i can create two records from two different classes...
PS1: equipment_id & type are required fields, but i don't understand how does it work ...
If what you mean is how does the list containing a single tuple [(4, vals['task_idd'])] give the desired result here is my understanding.
When Odoo is either creating or writing to a record which is a relation field Odoo uses a command syntax which is the structure you used in your code. Basically when writing or creating a related field from the perspective of any particular record Odoo tries to take away the ambiguity by creating a specific series of commands to use in these circumstances.
For instance if you need to write to a One2many field how is Odoo supposed to know if your are adding a new record to the list of many other records or are you saying that the list of related records is this new record you have referenced in your code.
So imagine you have a tree with a One2many relation with its Apples. If you were writing to a database recording another apple for the tree are you saying that this apple is to be added to the list of existing apples or is it replacing the existing list and should be considered the only apple that belongs to the tree.
So Odoo uses this tuple structure and has a process for parsing the tuple and determining how to handle its values and what to write to the database.
Here is a screen shot of the documentation Odoo provides on the matter. Here is the link to the page

What are the security risks if I disclose database field name to web user interface?

I want make the program more simple, so I use table's field name as name in input html,
And then I can save some time for mapping input name to database field name
But, are there security risks if user know my field name?
(Suppose SQL injection have handled in the server program)
Update 1:
I am not going to around the field name validation
I just don't want to do something like this
$uid=$_POST['user_id'];
$ufname=$_POST['user_first_name'];
$ulname=$_POST['user_last_name'];
If I do this
$user_id=$_POST['user_id'];
$user_first_name=$_POST['user_first_name'];
$user_first_name=$_POST['user_last_name'];
I can save coding time, and don't need to think two names for one data, and reduce bug.
and I can also do something like this to save more time as I just type the name once.
$validField=array("user_id","user_first_name","user_last_name");
foreach ($validField as $field) {
$orm[$field]=$field;
}
This can also valid the field name
so I think that hacks are no way to get my unpublished fields
I can save some time for mapping input name to database field name.
If you save time mapping input names to database field names, you would need to spend a roughly equivalent time validating that the field names are, in fact, among the fields that the users can access in your database. There is no way around this validation, because otherwise your DB is exposed to hacks that try and get your unpublished fields, such as IDs and hashes. This is pretty bad, so you would need to build that validation layer.
On the other hand, if you do a mapping from meaningless IDs to meaningful, then you do not need validation, because it is your program that produced the meaningful IDs. Essentially, the validation step is built into the process.