I need to filter my query with categories table which has many2many relation with another table. Is it possible to filter query with many2many relation?
Table res_partner
has many2many field category_id
relating to table res_partner_category.res_partner
, or let's just say partners can have many categories. What I need is to filter res_partners
table where it has category named 'business' or 'retail'. If it doesn't have any of these categories, it should not be shown.
Also there is another field in res_partner
which is category_value_ids
and has one2many
relation with res_partners_category_value
:
res_partner
has following fields with relations:
category_id
tores_partner_category
(many2many)category_value_ids
tores_partner_category_value
(one2many)name
(char)
res_partner_category
has following fields with relations:
partner_ids
tores_partner
(many2many)name
(char)
res_partner_category_value
has following fields with relations:
category_group_id
tores_partner_category
(many2one)category_id
tores_partner_category
(many2one)object_id
tores_partner
(many2one)
But if I try to use res_partner_category_value
table in SQL query I get error that I can't use it in query.
So for example, if there are 4 partners with these categories:
- first: categ1, categ2, business
- second: retail
- third: retail, business
- fourth: categ1, categ2
The query should return first, second and third partners.
One person told me it's not possible to filter like this with many2many relation. So I wonder is it really not possible or just complicated?
EDIT:
I found one more table called res_partner_category_rel
. I didn't see it, because in Openerp administration interface, where you can see all objects of database, that table is not shown. You can only see it directly through database.
So I was confused by this "missing" table:
res_partner_category_rel:
partner_id
(many2one)category_id
(many2one)
This is the test case you should have provided:
CREATE TABLE partner (
partner_id serial PRIMARY KEY
, partner text
);
INSERT INTO partner (partner) VALUES
('partner1')
, ('partner2')
, ('partner3')
, ('partner4')
;
CREATE TABLE category (
category_id serial PRIMARY KEY
, category text
);
INSERT INTO category (category) VALUES
('categ1')
,('categ2')
,('business')
,('retail');
CREATE TABLE partner_category (
partner_id int REFERENCES partner(partner_id)
, category_id int REFERENCES category(category_id)
, CONSTRAINT cat_pk PRIMARY KEY (partner_id, category_id)
);
INSERT INTO partner_category (partner_id, category_id) VALUES
(1,1), (1,2), (1,3)
,(2,4)
,(3,3), (3,4)
,(4,1), (4,2);
And this is the query you are after (one of many possible variants):
SELECT p.*
FROM partner p
WHERE EXISTS (SELECT * FROM partner_category pc
WHERE pc.partner_id = p.partner_id AND pc.category_id = 3)
OR EXISTS (SELECT * FROM partner_category pc
WHERE pc.partner_id = p.partner_id AND pc.category_id = 4)
ORDER BY p.partner_id;
The key word here is relational division. We have assembled a whole arsenal of queries to deal with this class of problems under this related question:
As you already noticed, the many2one category_id
is not represented in the database as a table field, but as a table relating Partners and Categories.
The SQL you need could look like this:
SELECT p.*
FROM res_partner p
INNER JOIN res_partner_category_rel rel ON p.id = rel.partner_id
INNER JOIN res_partner_category c ON rel.category_id = c.id
WHERE c.id in (3,4)
If you want to do the filter in the python object, the usual search
call should work:
list_ids = partner_model.search(cr, uid, [('category_id', 'in', [3,4])])
As a bonus, since Categories are organized in a tree, you could get those categories and all their children using:
list_ids = partner_model.search(cr, uid, [('category_id', 'child of', [3,4])])
来源:https://stackoverflow.com/questions/13253420/many-to-many-relation-filter