Introduction to actors

Tables and choicelists have certain things in common. When we refer to them in general, then we call them actors.

This is a tested document. The following instructions are used for initialization:

>>> from lino import startup
>>> startup('lino_book.projects.noi1e.settings.demo')
>>> from lino.api.doctest import *

Actor types

The most common type of actors table actors.

But not all actors are tables. Another type of actors are frames, display some data in some other form. One such frame actor is the calendar panel, another one is, used to display reports.

table actor

An actor that operates on a list of "rows".

We happen to simply refer to a table actor as "table", but of course we must not mix them up with database table.

database actor

A table actor that is connected to a database table.

Identifying actors

Actors are identified by their app_label.ClassName. Similar to Django's models they are globally known unique class objects.

Lino collects actors during site startup in a way similar to how Django collects models. Every subclass of lino.core.actors.Actor that is defined somewhere in your code, will be "registered" into the global models namespace rt.models.

It makes no difference whether you import them or access them via rt.models. Let's verify this for the lino_xl.lib.working.WorkedHours actor:

>>> from lino_xl.lib.working.models import WorkedHours
>>> rt.models.working.WorkedHours is WorkedHours

The advantage of accessing them via rt.models is that your code is open to extensions.

Actors are never instantiated, we use only the class objects.

>>> str(WorkedHours)
>>> repr(WorkedHours)

Getting a list of all actors

When Lino starts up, it automatically discovers the installed plugins and registers each subclass of Actor as an actor.

>>> len(actors.actors_list)

Some of the actors are abstract, i.e. they are used as base classes for other actors:

>>> len([a for a in actors.actors_list if a.is_abstract()])

The actors aren't collected only in this global list but also at different places depending on their type.

The most common actors are database tables. Here we differentiate between "master tables", "slave tables" and "generic slave tables":

>>> from lino.core import kernel
>>> len(kernel.master_tables)
>>> kernel.master_tables[0]
>>> len(kernel.slave_tables)
>>> kernel.slave_tables[0]
>>> list(sorted(kernel.generic_slaves.values(), key=str))
[,, lino.modlib.changes.models.ChangesByMaster, lino.modlib.changes.models.ChangesByObject, lino.modlib.checkdata.models.ProblemsByOwner, lino.modlib.comments.ui.CommentsByRFC, lino.modlib.comments.ui.MentionsByOwner, lino_xl.lib.excerpts.models.ExcerptsByOwner, lino.modlib.gfks.models.HelpTextsByModel, lino_xl.lib.invoicing.models.InvoicingsByGenerator, lino.modlib.uploads.models.UploadsByController]
>>> for a in kernel.generic_slaves.values():
...    assert a not in kernel.slave_tables
...    assert a in actors.actors_list

Another category are virtual tables. For example lino.modlib.users.UserRoles lino_xl.lib.working.WorkedHours lino.modlib.gfks.BrokenGFKs lino.modlib.gfks.BrokenGFKs

>>> kernel.virtual_tables  
[lino.modlib.about.models.SiteSearch, lino.modlib.gfks.models.BrokenGFKs,
lino.modlib.gfks.models.BrokenGFKsByModel, lino_xl.lib.calview.ui.MonthlySlave,
lino_xl.lib.calview.ui.DailyView, lino_xl.lib.calview.ui.WeeklyView,
lino_xl.lib.calview.ui.MonthlyView, lino_xl.lib.working.ui.WorkedHours,
lino_xl.lib.ledger.ui.ExpectedMovements, lino_xl.lib.ledger.ui.DebtsByAccount,
lino_xl.lib.ledger.ui.DebtsByPartner, lino_xl.lib.ledger.ui.Debtors,
lino_xl.lib.ledger.ui.Creditors, lino.modlib.users.desktop.UserRoles,

Another category are choicelists

>>> len(kernel.CHOICELISTS)
>>> list(sorted(kernel.CHOICELISTS.items()))[7]
>>> for a in kernel.CHOICELISTS.values():
...    if a not in actors.actors_list:
...        print(a)

And a last category are what we call "frames":

>>> kernel.frames_list
[lino.modlib.about.models.About, lino.modlib.system.models.Dashboard]