Introducing the Site class

Your application is defined by its Site class

As explained in Lino and your Django settings and The Lino Polls tutorial, a Lino site is when a Django settings module has a variable named SITE, and this variable must contain an instance of some subclass of the lino.core.site.Site class.

This top-level Site class is the ancestor of all Lino applications. It is designed to be subclassed by the application developer, then imported into a local settings.py, where a site maintainer may possibly subclass it another time. A Lino site starts to "live" when such a Site class gets instantiated in a Django settings module.

This concept brings an additional level of encapsulation to Django. Django settings usually contain simple values (strings, integers, or lists or dictionaries thereof). But Lino's SITE setting holds a Python object, with methods that can be called by application code at runtime.

To hook this into Django, imagine the Site class as a kind of a "project model". Read What is an application? if you wonder why we chose that name.

In other words, the central and fundamental definition of a Lino application is formulated by a Site class object. This Site class object is not defined in a Django settings module but as part of the Python package that implements your application. For example, the Site class for Lino Voga is defined in the module lino_voga.lib.voga.settings.

Note that this module defines a Site class object but does not instantiate it. You can import this module into a Django settings module, but you cannot use it directly as a settings module. The following attempt can only fail:

>>> from lino import startup
>>> startup('lino_voga.lib.voga.settings')
>>> from lino.api.rt import *
Traceback (most recent call last):
...
AttributeError: 'Settings' object has no attribute 'SITE'

In your Site class you define some general description of your application.

class lino.core.site.Site
title

The title to appear in the browser window. If this is None, Lino will use verbose_name as default value.

verbose_name

The name of this application, to be displayed to end users at different places.

Note the difference between title and verbose_name:

IOW, the title is rather for usage by a site maintainer, while the verbose_name is rather for usage by the application developer.

version

An optional version number.

url

The URL of the website that describes this application. Used e.g. in a Site ‣ About dialog box.

site_version(self)

Used in footnote or header of certain printed documents.

welcome_text(self)

Returns the text to display in a console window when this application starts.

using_text(self)

Text to display in a console window when Lino starts.

How Lino builds the INSTALLED_APPS setting

A Lino application is usually meant to install a given set of Django "apps" (i.e. what's in the INSTALLED_APPS setting). An application is a collection of plugins that make up a whole. To define this collection, the application developer usually overrides the Site.get_installed_apps() method.

Lino calls this method once at startup, and it expects it to yield a list of strings. Lino then adds some more "system" plugins and stores the resulting list into your INSTALLED_APPS setting.

Additional local plugins

An optional second positional argument can be specified by the site maintainer in order to specify additional local plugins. These will go into the INSTALLED_APPS setting, together with any other plugins needed by them.

>>> from lino_book.projects.min1.settings import Site
>>> pseudoglobals = {}
>>> Site(pseudoglobals, "lino_xl.lib.events")  
<lino_book.projects.min1.settings.Site object at ...>
>>> print('\n'.join(pseudoglobals['INSTALLED_APPS']))
... 
lino
django.contrib.staticfiles
lino.modlib.about
lino.modlib.jinja
lino.modlib.bootstrap3
lino.modlib.extjs
lino.modlib.printing
lino.modlib.system
lino.modlib.users
lino.modlib.office
lino_xl.lib.xl
lino_xl.lib.countries
lino_xl.lib.contacts
lino_xl.lib.events
django.contrib.sessions

As an application developer you won't specify this argument, you should specify your installed plugins by overriding get_installed_apps.

class lino.core.site.Site
Noindex

get_installed_apps(self)

Yield the list of apps to be installed on this site.

Each item must be either a string or a generator to be iterated recursively (again expecting either strings or generators of strings).

Lino will call this method exactly once when the Site instantiates. The resulting list of names will then possibly altered by the get_apps_modifiers() method before being assigned to the INSTALLED_APPS setting.

get_plugin_configs(self)

Return a series of plugin configuration settings.

This is called before plugins are loaded. rt.plugins is not yet populated.

The method must return an iterator that yields tuples with three items each: The name of the plugin, the name of the setting and the value to set.

Example:

def get_plugin_configs(self):
    yield super(Site, self).get_plugin_configs()
    yield ('countries', 'hide_region', True)
    yield ('countries', 'country_code', 'BE')
    yield ('vat', 'declaration_plugin', 'lino_xl.lib.bevats')
    yield ('ledger', 'use_pcmn', True)
    yield ('ledger', 'start_year', 2014)
get_apps_modifiers(self, **kwargs)

Override or hide individual plugins of the application.

Deprecated because this approach increases complexity instead of simplifying things.

For example, if your site inherits from lino.projects.min2:

def get_apps_modifiers(self, **kw):
    kw = super(Site, self).get_apps_modifiers(**kw)
    kw.update(sales=None)
    kw.update(courses='my.modlib.courses')
    return kw

The default implementation returns an empty dict.

This method adds an additional level of customization because it lets you remove or replace individual plugins from INSTALLED_APPS without rewriting your own get_installed_apps().

This will be called during Site instantiation and is expected to return a dict of app_label to full_python_path mappings which you want to override in the list of plugins returned by get_installed_apps().

Mapping an app_label to None will remove that plugin from INSTALLED_APPS.

It is theoretically possible but not recommended to replace an existing app_label by an app with a different app_label. For example, the following might work but is not recommended:

kw.update(courses='my.modlib.MyActivities')