Search code examples
pythontryton

What does mean for sub_ids in grouped_slice(ids) in Tryton?


I want to understand an instruction that I have seen a lot. What does for sub_ids in grouped_slice(ids) mean in Tryton?

Here is a fragment of a method where such instruction is used:

@classmethod
def get_duration(cls, works, name):
    pool = Pool()
    Line = pool.get('timesheet.line')
    transaction = Transaction()
    cursor = transaction.connection.cursor()
    context = transaction.context

    table_w = cls.__table__()
    line = Line.__table__()
    ids = [w.id for w in works]
    durations = dict.fromkeys(ids, None)
    where = Literal(True)
    if context.get('from_date'):
        where &= line.date >= context['from_date']
    if context.get('to_date'):
        where &= line.date <= context['to_date']
    if context.get('employees'):
        where &= line.employee.in_(context['employees'])

    query_table = table_w.join(line, 'LEFT',
        condition=line.work == table_w.id)

    for sub_ids in grouped_slice(ids):
        red_sql = reduce_ids(table_w.id, sub_ids)
        cursor.execute(*query_table.select(table_w.id, Sum(line.duration),
                where=red_sql & where,
                group_by=table_w.id))
        for work_id, duration in cursor:
            # SQLite uses float for SUM
            if duration and not isinstance(duration, datetime.timedelta):
                duration = datetime.timedelta(seconds=duration)
            durations[work_id] = duration
    return durations

Solution

  • grouped_slice is a function we use in tryton to read a list of objects in several subs sets (the default number depends on the database backend. For example the value is 2000 in the PostgreSQL backend).

    This is used to limit the number of parameters that we pass to the database because this may cause some issues when the number of input records is bigger than the max number of parameters accepted by the sql driver.

    Here is a simple example which provides a visual representation of how everything works:

    >>> from trytond.tools import grouped_slice
    >>> ids = list(range(0, 30))
    >>> for i, sub_ids in enumerate(grouped_slice(ids, count=10)):
    ...     print("Loop", i, ','.join(map(str, sub_ids)))
    ... 
    Loop 0 0,1,2,3,4,5,6,7,8,9
    Loop 1 10,11,12,13,14,15,16,17,18,19
    Loop 2 20,21,22,23,24,25,26,27,28,29
    
    

    As you see we have a list of 30 ids, which are processed in sets of 10 (as I used 10 as count argument).