What is the best way to get distinct order ids from the order lines?

Asked by Numérigraphe

Often in the addons we see functions like this:
    def _get_order(self, cr, uid, ids, context={}):
        result = {}
        for line in self.pool.get('sale.order.line').browse(cr, uid, ids, context=context):
            result[line.order_id.id] = True
        return result.keys()

That reads the order ids of all the selected lines from the database, and uses a dictionary to make the values distinct.

First, can't we just read() and use a set to make values distinct?

Second, is there not a way to just do a "SELECT DISTINCT" on the database and not have to loop?

Lionel

Question information

Language:
English Edit question
Status:
Answered
For:
Odoo Addons (MOVED TO GITHUB) Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:

This question was reopened

Revision history for this message
Jay Vora (Serpent Consulting Services) (jayvora) said :
#1

Hello Lionel,

I guess you are absolutely right.

I salute you for this thread. We should use cr.execute('select distinct order_id.....') here.

The aim is to get the key as sale order id only and this change propsed by you will really help to speed up if the SO has many lines.

Thanks again.

Revision history for this message
Olivier Dony (Odoo) (odo-openerp) said :
#2

Good point indeed, we can add it to the guidelines with both proposed solutions (read + set or select distinct), with examples to help people choose the best solution.

Indeed, in this specific context using a SELECT DISTINCT is fine, but normally we advice people to always use the ORM in order to correctly apply all the security rules and ORM features, and as importantly to avoid writing SQL code all over the place (and avoid introducing SQL injection vectors, etc.)

See also these existing guidelines 2.3 and 2.4:
   http://doc.openerp.com/contribute/15_guidelines/coding_guidelines.html (as soon as the website is back)

Lionel, can you contribute a new guideline for the Coding Guidelines with this example and these explanations, if you know how?

Thanks,

Revision history for this message
Numérigraphe (numerigraphe) said :
#3

I think the best would be to have add a parameter "disctint=True" to the search() method of the ORM.
I'll file a bug for that.
Lionel

Revision history for this message
Numérigraphe (numerigraphe) said :
#4

Thanks for your answers.
Is this the right way to do it with a SQL query?
    def _get_orders(self, cr, uid, ids, context=None):
        """Return the list of distinct Order ids in the Order Lines."""
        cr.execute("""
            SELECT DISTINCT order_id
            FROM sale_order_line
            WHERE id IN %s""",
            tuple(ids))
        return [x[0] for x in cr.fetchall()]

Lionel

Revision history for this message
Numérigraphe (numerigraphe) said :
#5

Sorry, that didn't work - would it be right this way?
    def _get_orders(self, cr, uid, ids, context=None):
        """Return the list of distinct Order ids in the Order Lines."""
        cr.execute("""
            SELECT DISTINCT order_id
            FROM sale_order_line
            WHERE id IN %s""",
            (tuple(ids),)
        )
        return [x[0] for x in cr.fetchall()]
Lionel

Revision history for this message
Olivier Dony (Odoo) (odo-openerp) said :
#6

Numerigraphe wrote:
> def _get_orders(self, cr, uid, ids, context=None):
> """Return the list of distinct Order ids in the Order Lines."""
> cr.execute("""
> SELECT DISTINCT order_id
> FROM sale_order_line
> WHERE id IN %s""",
> (tuple(ids),)
> )
> return [x[0] for x in cr.fetchall()]

That looks okay.

And for the Python version (which I really think should be the default choice in most cases unless/until we provide an API for distincts), you could have something like this using a nice generator comprehension:

   return set(line['order_id'] for line in self.read(cr, uid, ids, ['order_id'])

or even simpler using a more elegant browse:

   return set(line.order_id for line in self.browse(cr, uid, ids))

Looks much better than raw SQL code if you ask me, and comes with all the advantages of the ORM, as explained previously.

Can you help with this problem?

Provide an answer of your own, or ask Numérigraphe for more information if necessary.

To post a message you must log in.