Introduction to plugins¶
See Plugins for a list of the plugins defined in Lino and the XL.
A plugin in Lino corresponds to what Django calls an "application". See also What is an application?.
The plugin developer defines a plugin in the
__init__.py file of the
package. Lino expects this file to define a class named
inherits from the abstract base
Plugin class is the central description
of your plugin.
Here is a fictive example:
from lino.api import ad, _ class Plugin(ad.Plugin): verbose_name = _("Better calendar") extends = 'mylib.cal' needs_plugins = ['lino_xl.lib.contacts'] def setup_main_menu(self, site, user_type, m): m = m.add_menu(self.app_label, self.verbose_name) m.add_action('cal.Teams') m.add_action('cal.Agendas')
A plugin can depend on other plugins by specifying them in the
attribute. This means that when you install this plugin, Lino will
automatically install these other plugins as well
A plugin can define a set of menu commands using methods like
setup_main_menu. This is explained in
The application menu.
A plugin that extends another plugin can optionally extend one or multiple
database models defined by the parent plugin. If it does so, it must declare
their names in
Django developers are used to code like this:
from myapp.models import Foo def print_foo(pk=1): print(Foo.objects.get(pk=pk))
In Lino we prefer to use the
rt.models dict as
from lino.api import rt def print_foo(pk=1): Foo = rt.models.myapp.Foo print(Foo.objects.get(pk=pk))
This approach has the advantage of providing Plugin inheritance. One of the basic reasons for using plugins is that another developer can extend it and use their extension instead of the original plugin. Which means that the plugin developer does not know (and does not want to know) where the model classes are actually defined.
rt.models is populated only
after having imported the models. So you cannot use it at the
module-level namespace of a
models.py module. For example
the following variant of above code would not work:
from lino.api import rt Foo = rt.models.foos.Foo # error `AttrDict has no item "foos"` def print_foo(pk=1): print(Foo.objects.get(pk=pk))
Plugin descriptors get defined and configured before Django models start to
load. Lino creates one
Plugin instance for every installed plugin and
makes it globally available in
dd.plugins.FOO (where FOO is the
app_label of the plugin).
Plugin class is comparable to Django's AppConfig class,
which has been added in version 1.7., but there is at least one
important difference: in Lino the
Plugin instances for
all installed plugins are available (in
dd.plugins) before Django starts to load the
models.py. This is possible because Plugins are
__init__.py files of your plugins. As a
consequence, unlike Django's AppConfig, you cannot define a
Plugin in your
models.py file, you must define it in
Plugins can have attributes for holding configuration settings that are not meant to configured by site users via the web interface.
For example, the
countries.country_code setting is defined as
... class Plugin(ad.Plugin): ... country_code = 'BE'
The values of plugin attributes can be configured at three levels.
As a core developer you specify a hard-coded default value.
class Site(Site): def get_plugin_configs(self): yield super().get_plugin_configs() yield 'countries', 'country_code', 'FR' yield 'contacts', 'hide_region', True
The old style using
Site.setup_plugins() still works but is deprecated:
class Site(Site): def setup_plugins(self): super().setup_plugins() self.plugins.countries.configure(country_code='BE') self.plugins.contacts.configure(hide_region=True)
using one of the following methods:
by overriding the Site class as described above for application developers
by setting the value directly after instantiation of your