Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More

The Site class

See also More about the Site class and More about plugins and The languages of a Lino site.

Lines starting with >>> in this document are code snippets that get tested as part of our development workflow.

>>> from lino import startup
>>> startup('lino_book.projects.min1.settings')
>>> from lino.api.doctest import *
class lino.core.site.Site

The base class for a Lino application.

In your settings.py file you instantiate a subclass of this and assign that instance to a variable named SITE. See Create your first Lino site for usage example.

This class is designed to be overridden by both application developers and server administrators.

__init__(self, settings_globals=None, local_apps=[], **kwargs)

settings_globals is the globals() dictionary of the settings.py.

init_before_local(self, settings_globals, local_apps)

If your project_dir contains no models.py, but does contain a fixtures subdir, then Lino automatically adds this as a local fixtures directory to Django’s FIXTURE_DIRS.

But only once: if your application defines its own local fixtures directory, then this directory “overrides” those of parent applications. E.g. lino_noi.projects.care does not want to load the application-specific fixtures of lino_noi.projects.team.


Return a dict to be set as the DATABASE setting.

The default behaviour uses SQLite (1) on a file named default.db in the site_dir if that attribute is specified, and (2) in :memory: when site_dir is None.

And alternative might be for example:

def get_database_settings(self):
    return {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'test_' + self.project_name,
            'USER': 'django',
            'PASSWORD': os.environ['MYSQL_PASSWORD'],
            'HOST': 'localhost',
            'PORT': 3306,
            'OPTIONS': {
               "init_command": "SET storage_engine=MyISAM",

Load all plugins and build the INSTALLED_APPS setting for Django.

This includes a call to get_plugin_modifiers() and get_installed_plugins().


Collect requirements from plugins. Add some more requirements which depend on options in the local settings.py file.


Deprecated. Use get_plugin_configs() instead.

This method is called exactly once during site startup, after load_plugins() but before populating the models registry.

See More about plugins.


When LINO_CACHE_ROOT is set, Lino adds a stamp file called lino_cache.txt to every project’s cache directory in order to avoid duplicate use of same cache directory.


A small text file with one line of text which contains the path of the project which uses this cache directory.

set_user_model(self, spec)

This can be called during the on_init of plugins that provide user management (the only plugin that does this is currently lino.modlib.users).


Returns the authentication method used on this site. This is one of None, ‘remote’ or ‘session’.

It depends on the values in user_model, default_user and remote_user_header.

It influences the results of get_middleware_classes() and get_installed_plugins(), and the content of AUTHENTICATION_BACKENDS.


Start up this Site.

You probably don’t want to override this method as it might be called several times. e.g. under mod_wsgi: another thread has started and not yet finished startup().

If you want to run custom code on site startup, override do_site_startup().


This method is called exactly once during site startup, just between the pre_startup and the post_startup signals. A hook for subclasses.

TODO: rename this to on_startup?

get_settings_subdirs(self, subdir_name)

Yield all (existing) directories named subdir_name of this Site’s project directory and its inherited project directories.

makedirs_if_missing(self, dirname)

Make missing directories if they don’t exist and if make_missing_dirs is True.

is_abstract_model(self, module_name, model_name)

Return True if the named model is declared as being extended by lino.core.plugin.Plugin.extends_models.

Typical usage:

class MyModel(dd.Model):
     class Meta:
         abstract = dd.is_abstract_model(__name__, 'MyModel')

See Plugin inheritance.

is_installed(self, app_label)

Return True if INSTALLED_APPS contains an item which ends with the specified app_label.

setup_model_spec(self, obj, name)

If the value of the named attribute of obj is a string, replace it by the model specified by that string.

Example usage:

# library code:
class ThingBase(object):
    the_model = None

    def __init__(self):
        settings.SITE.setup_model_spec(self, 'the_model')

# user code:
class MyThing(ThingBase):
    the_model = "contacts.Partner"
on_each_app(self, methname, *args)

Call the named method on the models.py module of each installed app.

Note that this mechanism is deprecated. It is still used (on names like setup_workflows and setup_site) for historical reasons but will disappear one day.

for_each_app(self, func, *args, **kw)

Call the given function on each installed plugin. Successor of on_each_app().

This also loops over plugins that don’t have a models module and the base plugins of plugins which extend some plugin.

demo_date(self, *args, **kwargs)

Deprecated. Should be replaced by today(). Compute a date using lino.utils.date_offset() based on the process startup time (or the_demo_date if this is set).

Used in Python fixtures and unit tests.

today(self, *args, **kwargs)

Almost the same as datetime.date.today().

One difference is that the system’s today is replaced by the_demo_date if that attribute is set.

Another difference is that arguments can be passed to add some offset. See atelier.utils.date_offset().

This feature is being used in many test cases where e.g. the age of people would otherwise change.


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


Return the text to display in a console window when Lino starts.


Return the name of the application running on this site, including the version (if a version is specified).

Used in footnote or header of certain printed documents.

install_migrations(self, *args)

See lino.utils.dpy.install_migrations().

parse_date(self, s)

Convert a string formatted using date_format_strftime or date_format_extjs into a (y,m,d) tuple (not a datetime.date instance). See /blog/2010/1130.

parse_time(self, s)

Convert a string into a datetime.time instance using regex. only supports hours and min, not seconds.

parse_datetime(self, s)

Convert a string formatted using datetime_format_strftime or datetime_format_extjs into a datetime.datetime instance.


Hook for subclasses to add or modify actions.

get_used_libs(self, html=None)

Yield a list of (name, version, url) tuples describing the third-party software used on this site.

This function is used by using_text() and welcome_html().


This function is called when a Site object gets instantiated, i.e. while Django is still loading the settings. It analyzes the languages attribute and converts it to a tuple of LanguageInfo objects.


Reduce Django’s LANGUAGES to my languages. Note that lng.name are not yet translated, we take these from django.conf.global_settings.

is_imported_partner(self, obj)

Return whether the specified Partner instance obj is to be considered as imported from some legacy database.


Used in footnote or header of certain printed documents.

The convention is to call it as follows from an appy.pod template (use the html function, not xhtml)

do text
from html(settings.SITE.site_header())

Note that this is expected to return a unicode string possibly containing valid HTML (not XHTML) tags for formatting.

get_dashboard_items(self, user)

Expected to yield a sequence of items to be rendered on the dashboard (admin_main.html).

The default implementation calls get_dashboard_items on every installed plugin and yields all items.

The items will be rendered in that order, except if lino.modlib.dashboard is installed to enable per-user customized dashboard.


This property holds a cached version of the one and only SiteConfig row that holds site-wide database-stored and web-editable Site configuration parameters.

If no instance exists (which happens in a virgin database), we create it using default values from site_config_defaults.

This is None when lino.modlib.system is not installed.

It can also be None when startup is not done, which can happen e.g. on an asgi web server.

get_config_value(self, name, default=None)

Return the value of the named SiteConfig field.

When site_config is None for whatever reason, this returns the specified default value, which defaults to None (site_config_defaults is not looked up in this case).


Clear the cached SiteConfig instance.

This is needed e.g. when the test runner has created a new test database.

The list of quick links.

This is lazily created when first accessed.

Yield the quick links that are visible for the given user type.

Return or yield a sequence of quick link descriptors to be added to the list of quick links.

Override this to define application-specific quick links.

Customize the list of quick links. Override this to define application-specific quick links.

Default implementation calls get_quicklinks and setup_quicklinks for each installed plugin.

The quicklinks yielded by get_quicklinks will be added before calling setup_quicklinks.

get_site_menu(self, user_type)

Return this site’s main menu for the given UserType. Must be a lino.core.menus.Toolbar instance. Applications usually should not need to override this.

setup_menu(self, user_type, main)

Set up the application’s menu structure.

See More about the application menu and How plugins build the application menu.


Yields the strings to be stored in the MIDDLEWARE_CLASSES setting.

In case you don’t want to use this method for defining MIDDLEWARE_CLASSES, you can simply set MIDDLEWARE_CLASSES in your settings.py after the Site has been instantiated.

Django and standard HTTP authentication

get_main_html(self, ar, **context)

Return a chunk of html to be displayed in the main area of the admin index. The default implementation renders the admin_main.html template.

build_site_cache(self, force=False, later=False, verbosity=1)

Populate the site cache, especially the lino*.js files, one per user user type and language.

  • force: rebuild the files even if they are up to date

  • later: don’t rebuild now, just touch the settings.py so that they get rebuild next time.

get_welcome_messages(self, ar)

Yields a list of “welcome messages” (see lino.core.actors.Actor.get_welcome_messages()) of all actors. This is being called from admin_main.html.

add_welcome_handler(self, func, actor=None, msg=None)

Add the given callable as a “welcome handler”. Lino will call every welcome handler for every incoming request, passing them a BaseRequest instance representing this request as positional argument. The callable is expected to yield a series of messages (usually either 0 or 1). Each message must be either a string or a E.span element.

welcome_html(self, ui=None)

Return a HTML version of the “This is APPLICATION version VERSION using …” text. to be displayed in the About dialog, in the plain html footer, and maybe at other places.

login(self, username=None, **kw)

Open a session as the user with the given username.

For usage from a shell or a tested document. Does not require any password because when somebody has command-line access we trust that she has already authenticated.

It returns a BaseRequest object.

get_letter_date_text(self, today=None)

Returns a string like “Eupen, den 26. August 2013”.

decfmt(self, v, places=2, **kw)

Format a Decimal value using lino.utils.moneyfmt(), but applying the site settings lino.Lino.decimal_group_separator and lino.Lino.decimal_separator.

format_currency(self, *args, **kwargs)

Return the given number as a string formatted according to the site_locale setting on this site.

All arguments are forwarded to locale.locale().

lookup_filter(self, fieldname, value, **kw)

Return a models.Q to be used if you want to search for a given string in any of the languages for the given babel field.

get_plugin_setting(self, plugin_name, option_name, *default)

Return the given plugin setting if the plugin is installed, otherwise the provided default value.


An AttrDict with one entry for each installed plugin, mapping the app_label of every plugin to the corresponding lino.core.plugin.Plugin instance.

This attribute is automatically filled by Lino and available as dd.plugins already before Django starts to import models.py modules.


Old name for models. Deprecated.


An AttrDict which maps every installed app_label to the corresponding models.py module object.

This is also available as the shortcut rt.models.

See More about plugins


Until 20180926 this was a string like e.g. ‘beid’ in order to use a custom protocol for reading eid cards. Now it is deprecated. Use lino_xl.lib.beid.Plugin.urlhandler_prefix instead.


The default value for max_length of quantity fields.


The value to use as upload_to for the Upload.file field.

Default value is 'uploads/%Y/%m'.


The default value for the auto_fit_column_widths of tables in this application.


The locale to use for certain localized things on this site.

Used by format_currency().

This should be a string of type ‘<language>_<country>.<encoding>’, and it must have been generated previously. For example:

sudo locale-gen de_BE.utf8

Pointer to the config directories registry. See Introduction to config directories and lino.utils.config. Lino sets this attribute during site startup.


This attribute is available only after startup(). See lino.core.kernel.


Setting this to True turns this site in a readonly site. This means that DATABASES must point to the DATABASES of some other (non-readonly) site, and that initdb will do nothing.


A constant date to be used as reference by today() and demo_date().

Default value is None. If this is set, Lino shows a welcome message of style “We are running with simulated date set to Friday 22 May 2015.”

This is either None or a datetime.date object. If your settings.py specifies it as an int or a str, Lino converts it at site startup to a datetime.date using rstgen.utils.i2d().

Many demo projects have this set so that tested documents can rely on a constant reference date.


This is mentioned in 500.html.


A multi-line plain text description of up to 250 characters.

Common practice is to fill this from your SETUP_INFO.

It is listed on https://www.lino-framework.org/apps.html


Set this to False if you don’t want Lino to automatically create missing directories when needed. If this is False, Lino will raise an exception in these cases, asking you to create it yourself.


The directory where Lino stores local files.

See Lino and local files.


The Django project directory for this site.

See Lino and local files.


The root directory at which to build the Javascript and json cache files. See Lino and local files.


A nickname for this project.

This is used only when LINO_CACHE_ROOT is set, and only to set the site_dir. In that case all Lino projects in a given repository must have a unique project name.

If this is None, Lino will find a default value by splitting project_dir and taking the last part (or the second-last if the last part is ‘settings’.


This is a reference to the globals() dictionary of your settings.py file (the one you provided when instantiating the Site object).


The time when this Site has been instantiated, in other words the startup time of this Django process. Don’t modify this.


The list of top-level menu items. See More about the application menu and How plugins build the application menu.


Whether the process is currently loading data from a Python dump.

When loading from a python dump, application code should not generate certain automatic data because that data is also part of the dump.

This is normally False, but a Python dump created with pm dump2py explicitly calls install_migrations(), which sets this to True.

Application code should not change this setting except for certain special test cases.


Specifies the application’s project model.

A project in this context means what the users consider “the central most important thing that is used to classify most other things”. For example in Lino Avanti the “project” is a Client while in Lino Tera it is a therapy.

This can be either None (the default value) or the full name of the model used as “central project model” in this application.

If this is not None, all models that inherit from ProjectRelated will have an additional ForeignKey to this model.

TODO: convert this into a plugin setting of the office plugin?


The database model used for users. This is automatically set to 'users.User' when lino.modlib.users is installed.

Default value is None, meaning that this application has no user management. See also set_user_model()

See also users : user management.


Override used authorisation middlewares with supplied tuple of middleware class names.

If None, use logic described in Authentication


Whether the internal field names should be visible. ExtUI implements this by prepending them to the tooltip, which means that use_quicktips must also be True. Default is True.


Probably deprecated. Set this to True if you want that Lino never (re)builds the site cache, even when asked. This can be useful on a development server when you are debugging directly on the generated lino*.js. Or for certain unit test cases.


Whether to keep partly generated files in the the site cache.


Whether this site runs in demo mode.

Default value is False. On a production site you will of course take care to leave this to False.

See also demo_fixtures and the_demo_date and quick_startup.


Default values to be used when creating the site_config.

Usage example:

site_config_defaults = dict(default_build_method='appypdf')

Whether to include “experimental features”. Deprecated. lino_xl.lib.inspect


Whether to use “new” unicode symbols (e.g. from the Miscellaneous Symbols and Pictographs block) which are not yet implemented in all fonts.

Currently used by lino_noi.lib.noi.workflows


If this is True, certain Lino plugins use the deprecated silk icons library for representing workflows.

The recommended but not yet fully implemented “modern” style is to use unicode symbols instead of icons.


A site-wide option to disable everything that needs Java. Note that it is up to the plugins which include Java applications to respect this setting. Usage example is lino_xl.lib.beid.


Whether to use solr backend server for search document indexing.


The default build method to use when rendering printable documents.

This is the last default value, used only when default_build_method in SiteConfig is empty.


The list of fixtures to be loaded by the pm prep command. See also Introduction to demo fixtures.


The prefix to use for Django admin URLs. Leave this unchanged as long as https://gitlab.com/lino-framework/lino/blob/master/docs/tickets/70 is not solved.


The first hour of a work day.

Limits the choices of a lino.core.fields.CalendarTimeField.


The last hour of a work day.

Limits the choices of a lino.core.fields.CalendarTimeField.


Format (in ExtJS syntax) to use for displaying dates to the user. If you change this setting, you also need to override parse_time().

Default value is 'H:i'.

>>> settings.SITE.time_format_extjs

Alternative time entry formats accepted by ExtJS time widgets.

ExtJS default is:

“g:ia|g:iA|g:i a|g:i A|h:i|g:i|H:i|ga|ha|gA|h a|g a|g A|gi|hi|gia|hia|g|H|gi a|hi a|giA|hiA|gi A|hi A”

Lino’s extended default also includes:

“Hi” (1900) and “g.ia|g.iA|g.i a|g.i A|h.i|g.i|H.i” (Using . in replacement of “:”)


Format (in ExtJS syntax) to use for displaying dates to the user. If you change this setting, you also need to override parse_date().

Default value is 'd.m.Y'.

>>> settings.SITE.date_format_extjs

Alternative date entry formats accepted by ExtJS Date widgets.

>>> settings.SITE.alt_date_formats_extjs

Whether last name of persons should (by default) be printed with uppercase letters.

See lino.test_apps.human


Whether to use the Jasmine testing library.


Path to the Jasmine root directory. Only used on a development server if the media directory has no symbolic link to the Jasmine root directory and only if use_jasmine is True.


Whether to make use of Ext.QuickTips for displaying Help texts and internal field names (if show_internal_field_names).


Whether to make use of CSS tooltips when displaying help texts defined in lino.models.HelpText.


Whether to use VinylFox extensions for HtmlEditor. This feature was experimental and doesn’t yet work (and maybe never will). See /blog/2011/0523.


Default value for the preview_limit parameter of all tables who don’t specify their own one. Default value is 15.

>>> settings.SITE.preview_limit

The default format for rich textfields. Valid choices are 'plain' and 'html'.

See Text fields.


Default value for RichTextField.textfield_bleached.

See Bleaching.


A list of tag names that are to remain in HTML comments if bleaching is active.

See Bleaching.


A dictionary of key-values for tagname-attributes_list which are to remain in HTML comments if bleaching is active.

>>> pprint(settings.SITE.bleach_allowed_attributes)
{'a': ['href', 'title'],
 'abbr': ['title'],
 'acronym': ['title'],
 'p': ['href', 'title', 'align'],
 'span': ['class',

Username of the user to be used for all incoming requests. Setting this to a nonempty value will disable authentication on this site. The special value ‘anonymous’ will cause anonymous requests (whose user attribute is the AnonymousUser singleton).

See also get_auth_method().

This setting should be None when user_model is None.


The name of the header (set by the web server) that Lino should consult for finding the user of a request. The default value None means that HTTP authentication is not used. Apache’s default value is "REMOTE_USER".

No longer used since 20240518.


Whether to include functionality to read Belgian id cards using the official eid-applet. This option is experimental and doesn’t yet work. See /blog/2012/1105.


Whether to include functionality to read Estonian id cards. This option is experimental and doesn’t yet work.


Whether to use AwesomeUploader. This option was experimental and doesn’t yet work (and maybe never will).


Set this to True if actions should send debug messages to the client. These will be shown in the client’s Javascript console only.


The signal to which the log server should register its shutdown handler.

This is used when _history_aware_logging is enabled to log an info message when a process ends. And by the linod plugin to remove the socket file of the log server.

On a production server with linod.use_channels is True, this must be the same signal as the stopsignal setting in the program section of your supervisor config.

>>> settings.SITE.stopsignal

An e-mail address where users can get help. This is included in admin_main.html.


Lino usually catches any exception during startup (in create_layout_element) to report errors of style “Unknown element “postings.PostingsByController (‘postings’)” referred in layout <PageDetail on publisher.Pages>.”

Setting this to False is useful when there’s some problem within the framework.


Whether to raise BadRequest when master instance is not correctly specified. This was introducted in March 2023 and is not yet implemented everywhere.


This should be True unless this site is being used just for autodoc or similar applications.


Whether invalid values in a ChoiceList should raise an exception.

This should be True except for exceptional situations. Setting this to True won’t allow you to store invalid choicelist values in the database, but at least Lino will not raise an exception as soon as it reads an invalid value from existing data. This can happen e.g. after a code upgrade without data migration. In such a situation you may want to run make_snapshot.sh in order to migrate the data.


Site-wide default parameters for CSV generation. This must be a dictionary that will be used as keyword parameters to Python csv.writer()

Possible keys include:


Set this to either '.' or ',' to define wether to use comma or dot as decimal point separator when entering a DecimalField.


Decimal group separator for decfmt().


Format (in strftime syntax) to use for displaying dates to the user. If you change this setting, you also need to override parse_time().


Format (in strftime syntax) to use for displaying dates to the user. If you change this setting, you also need to override parse_date().


Format (in Javascript regex syntax) to use for displaying dates to the user. If you change this setting, you also need to override parse_date().


Format (in strftime syntax) to use for formatting timestamps in AJAX responses. If you change this setting, you also need to override parse_datetime().


Format (in ExtJS syntax) to use for formatting timestamps in AJAX calls. If you change this setting, you also need to override parse_datetime().


Whether to skip startup operations that are useful during development but not one production site.

master_site = None Another Site instance to be used as the master for this site. DATABASES and SECRET_KEY and the site_dir


A dictionary that maps model class names to the plugin which overrides them.

This is automatically filled at startup. You can inspect it, but you should not modify it. Needed for is_abstract_model().

The challenge is that we want to know exactly where every model’s concrete class will be defined before actually starting to import the models.py modules. That’s why we need extends_models.

This can be tricky, see e.g. 20160205.


Used internally by is_abstract_model(). Don’t modify.

A set of the full Python paths of all imported plugin modules. Not just the plugin modules themselves but also those they inherit from.



Simplified copy of django.utils.translation.to_locale, but we need it while the settings module is being loaded, i.e. we cannot yet import django.utils.translation. Also we don’t need the to_lower argument.

class lino.core.site.TestSite(Site)

Used to simplify doctest strings because it inserts default values for the two first arguments that are mandatory but not used in our examples.


from lino.core.site import Site
Site(globals(), ...)

from lino.core.site import TestSite as Site