Domain is used in Odoo to select records from a Model (database table) – in many different places:
- Menus / Windows Actions
- Form Views – to select records from a one2many or many2many
- Record Rules
- Filters (see below)
One way to see how it works is to create a new User-Defined Filter.
- e.g. We want to see orders from customers in California.
Create a user-defined filter
The simplest way to do this is to create a filter from the “front-end”, as explained here.
Creating from the ‘back-end’
Enable “developer mode“, navigate to Technical / User-defined Filters and click on “New”:

Select a model (in this case Sale Order) and click on “Add Filter”.

Now we can select a field on sale.order. If it’s a one2many field we can select fields on the Related model (database table).
For this example, we’ll select “State” from the Invoice address
We can enter the name of the state:

[["partner_invoice_id.state_id","=","California"]]

You can copy and paste this domain and use it elsewhere.
A slightly more complex example: all products that can be purchased or sold. This uses the logical OR symbol “|” :

["|", ["purchase_ok","=",True], ["sale_ok","=",True] ]
If there were three conditions you need to have OR twice (if there are four you need three ORs, and so on).
Other logical operators are:
- ‘&‘ = AND (this is the default so it is optional)
- ‘!‘ = NOT
There are many other operators:
- =, !=, >, >=, <, <=
- like, not like, ilike, not ilike
- in, not in
You can experiment with them in User-Defined Filters to get a better understanding of the syntax.
Examples
Select Purchase Orders but not RFQs:
[('state','not in',('draft','sent'))]
Multiple conditions
- Either
- Can be Purchased AND Can be Sold
- OR
- Landed Cost AND Service Type

["|", "&", ["purchase_ok","=",True], ["sale_ok","=",True], "&", ["landed_cost_ok","=",True], ["type","=","service"] ]
As explained above, the OR symbol “|” and the AND symbol “&” come before the conditions. For both of them, one symbol can be followed by two conditions.
Here’s an example (from a Record Rule for Sales Order lines) which has more than two conditions:
"['&', '&', ('state', 'in', ['sale', 'done']),
('is_service', '=', True),
'|', ('project_id','!=', False),
('task_id','!=', False)
]"
It starts with two ANDs because there are three conditions:
- The SO line status is either
sale
ordone
. - The SO line is for a service item (
is_service
=True
) - Either the project or task is specified
As you will see, this can become quite complex – but using Filters is a fairly easy way to try different combinations and eventually you should understand it!
Comparing with other fields
Domain can used to compare two fields rather than a field and a constant. For example, the Record Rule for “Sales / Own Documents only”:
['|',
('user_id','=',user.id),
('user_id','=',False)]
Note that the first field name is in quotes, the second one is not.
The first comparison is whether the User ID on the sales order is the current user. The second is whether there is a User ID on the sales order. So this will be true if:
- Sales order is for the current user OR
- Sales order has no assigned salesperson (user_id is blank)
The comparison can be with a field in another Model:
[('partner_id', '=', commercial_partner_id)]
As mentioned above there are many other operators, for example:
[ '|',
('company_id', '=', False),
('company_id', 'in', company_ids)
]
This will select records with no company specified (meaning they are shared) OR records for the current companies (selected in the multi-company widget as explained here)
[('type', 'not in', ['sale', 'purchase', 'cash', 'bank'])]
This will select records where the type is not any of those specified (this example is a filter on Account Journals)
A problem entering domains
Note that there are some limitations with domains if you enter them through the user interface.
In the above examples:
- Filters use a pop-up dialog box which makes it easier to enter domains, but at the cost of limiting the functionality that is available.
- Domains for Record Rules are entered in raw form, which is a little more difficult but allows more options.
It is possible to change the widget in the XML.
This is an extract from the XML for Automated Actions (View Name is “Automations”)
<field name="filter_pre_domain"
widget="domain"
options="{'model': 'model_name', 'in_dialog': True}"
attrs="{'invisible': [('trigger', 'not in',['on_write','on_create_or_write'])]}"/>
The change is simple: use the char_domain
widget instead
I’m curious what would be the best practice of the following use case:
People have access to the Accounting budget view they are responsible for and the corresponding analytic accounts are accessible to them but they shouldn’t be able to view other budgets and analytic accounts (not just invisible but complete denial of access via the Odoo error window).
The split in the budget is easy since you can work with the responsible user id and a domain record rule for Budget like [‘|’,
(‘user_id’,’=’,user.id),
(‘user_id’,’=’,False)
]
But limiting a specific analytic account to a specific user is hard to figure out, at least for me.
LikeLike
Anybody knows how to limit team members to view Helpdesk tickets of their own team, regardless if member is assigned to the ticket?
LikeLike
Is it possible to use self.env[model.name]. function () in Domain of record rules? I am always getting error.
LikeLike
I don’t understand your question. What are you are trying to achieve?
LikeLike
Good afternoon,
We have a single company setup and multiple outlets with each outlet with a POS. Currently, when the users log in, they are able to see all the POS outlets on their screen.
We would like them to see only the POS of their outlet. Currently, each outlet can see the records of other outlets too.
Can this be achieved through record rules. If so, how? Any help is appreciated
LikeLike
You can see an answer posted in this link below
https://www.odoo.com/forum/help-1/how-do-you-restrict-a-pos-user-from-viewing-other-user-s-orders-10637
LikeLike
Do we have ability to set domain on journal entry (invoices/bills..) so if we give a salesperson billing access rights he will only allowed to see his entries?
LikeLike
There is a salesperson field on the invoice and a Record Rule for the user access group Sales / User: Own Documents Only so I think it should be standard, no need to grant Billing access.
LikeLike
Hello there,
how can we use domains in qweb-pdf report templates?
any help is appreciated, Thanks.
LikeLike
Sorry, QWeb reports are a bit too much like programming for me, so I’ll let someone else answer that!
LikeLike
Hi odooers,
I am looking forward to achieve this:
Internal Users should only be able to see:
– contacts of people in the company
– contacts s/he creates
– contacts where s/he is appointed as salesperson
* only admin should see all contacts.
Example:
I have 3 users : Administrator, User-A and User-B
When accessing the Contacts module,
User-A should not see the contacts User-B or Administrator created, UNLESS User-A is the sales person.
I have tried to achieve this with record rules but that created a series of bugs all over the place.
Do you have any recommendations?
LikeLike