def navinfo(qs, elem):
    """Return a dict with navigation information for the given model
    instance `elem` within the given queryset.  The dictionary
    contains the following keys:
    
    :recno:   row number (index +1) of elem in qs
    :first:   pk of the first element in qs (None if qs is empty)
    :prev:    pk of the previous element in qs (None if qs is empty)
    :next:    pk of the next element in qs (None if qs is empty)
    :last:    pk of the last element in qs (None if qs is empty)
    :message: text "Row x of y" or "No navigation"

    """
    first = None
    prev = None
    next = None
    last = None
    recno = 0
    message = None
    #~ LEN = ar.get_total_count()
    if isinstance(qs, (list, tuple)):
        LEN = len(qs)
        id_list = [obj.pk for obj in qs]
        #~ logger.info('20130714')
    else:
        LEN = qs.count()
        # this algorithm is clearly quicker on queries with a few thousand rows
        id_list = list(qs.values_list('pk', flat=True))
    if LEN > 0:
        """
        Uncommented the following assert because it failed in certain circumstances 
        (see `/blog/2011/1220`)
        """
        #~ assert len(id_list) == ar.total_count, \
            #~ "len(id_list) is %d while ar.total_count is %d" % (len(id_list),ar.total_count)
        #~ print 20111220, id_list
        try:
            i = id_list.index(elem.pk)
        except __HOLE__:
            pass
        else:
            recno = i + 1
            first = id_list[0]
            last = id_list[-1]
            if i > 0:
                prev = id_list[i - 1]
            if i < len(id_list) - 1:
                next = id_list[i + 1]
            message = _("Row %(rowid)d of %(rowcount)d") % dict(
                rowid=recno, rowcount=LEN)
    if message is None:
        message = _("No navigation")
    return dict(
        first=first, prev=prev, next=next, last=last, recno=recno,
        message=message)


# class Handle(object):
#     """Base class for :class:`lino.core.tables.TableHandle`,
#     :class:`lino.core.frames.FrameHandle` etc.

#     The "handle" of an actor is responsible for expanding layouts into
#     sets of (renderer-specific) widgets (called "elements"). This
#     operation is done once per actor per renderer.

#     """
#     # def __init__(self):
#     #     self.ui = settings.SITE.kernel.default_ui

#     def setup(self, ar):
#         settings.SITE.kernel.setup_handle(self, ar)
#         # self.ui.setup_handle(self, ar)
dataset/ETHPy150Open lsaffre/lino/lino/core/utils.py/navinfo