Installation | Topics | Beyond Lino

The local settings.py file

This document explains how to organize, edit and manage your local configuration options. For a list of the actual options, see Site settings reference for maintainers

Overview

Every Lino site is defined by a Django settings module, usually defined in a file named settings.py, which is generated by getlino startsite.

As a server administrator you are responsible for modifying the settings.py file. It is not meant for being editable by the site operator (via the web interface) because a change might

  • require a database migration

  • have commercial consequences like a changed hosting price or a fee for modifying them.

This file contains configuration options that the site operator might want to discuss with their server administrator.

Types of configuration options

As a server administrator you should understand two types of options you can configure in a settings.py file.

site setting

A configuration option that can be set for a given Lino site by its server administrator.

For example the languages setting:

class Site(Site):
    languages = "en fr"
plugin setting

A configuration option that is used only by a given plugin.

For example the notify.remove_after setting:

def get_plugin_configs(self):
    yield super().get_plugin_configs()
    ...
    yield ('notify', 'remove_after', 24*7)

A configuration option that decides which plugins are to get installed cannot be a plugin setting because it must be known when the Site instantiates.

The name of a plugin setting contains a dot (.) and is of format app_label.attrname while a site setting has a name without a dot.

Modifying your local settings.py

To edit your local settings.py file, go to the project directory and start your preferred editor on it:

go mysite
nano settings.py

After modifying your settings.py you must run reload_services.sh to restart all services that use Lino.

A minimal Lino settings.py contains something like this:

from foo.bar.settings import *
SITE = Site(globals())
# more local settings here

That is, you import the default settings of some Lino application into your local settings module, including a Site class, then you instantiate that Site class and store this instance in a variable named SITE. Every Lino site requires a setting named SITE.

SITE

The instance of lino.core.site.Site (or a subclass thereof) that defines the application that is running on this site. The SITE setting is what turns a Django project into a Lino site.

The settings.py file must be valid Python syntax. One pitfall if you have no experience with Python is that indentation is important. Also make sure that your text editor doesn’t replace spaces by tabs.

In case of doubt, before restarting the server, you may issue the following command to test whether your settings.py is okay:

$ python manage.py validate

Editing the settings.py can require a database change

Every change in a settings.py file may potentially (but not necessarily) require a change the database structure.

For example the database is likely to change when you modify the line “from foo.bar.settings import *” because that switches to another application. Every application has its own database structure.

Or if you change the languages setting and your application uses multilingual database content.

Or certain plugin settings influence the database, for example accounting.has_payment_methods.

Adapting the database to your changes in the settings.py file is easy when this is just a demo site: you simply run pm prep and you’re done. On a production site you basically make a database snapshot before your change and restore that snapshot after the change (as for example in Upgrading a production site).

Inheriting settings

You might be surprised to see the following construct:

from foo.bar.settings import *

class Site(Site):
    title = "My title"

SITE = Site(globals())

We are just using a feature of the Python language that allows us to define a new class based on an existing class and having the same name as its parent.

A settings.py file generated by getlino also adds the following:

def get_plugin_configs(self):
    yield super(Site, self).get_plugin_configs()
    # example of local plugin settings:
    # yield ('accounting', 'start_year', 2018)

That is, you override the lino.core.site.Site.get_plugin_configs() method.

Lino dynamically creates your Django settings

The first argument of the instantiator must be the global namespace of your settings module (globals()). Lino uses this to fill “intelligent default values” to your settings module’s global namespace.

In other words, Lino is going to automatically set certain Django settings. Including for example INSTALLED_APPS and DATABASES.

Note that Lino writes to your settings module’s global namespace only while the Site class gets instantiated. So if for some reason you want to modify one of the settings, do it after your SITE=Site(globals()) line.

You’ve maybe heard that it is not allowed to modify Django’s settings once it has started. But there’s nothing illegal with this here because this happens before Django has seen your settings.py.

Lino does more than this. It will for example read the __file__ attribute of this, to know where your settings.py is in the file system.

Here are some of the Django setting for which Lino sets default values:

  • DATABASES : a SQLite database in a file default.db in your project directory. On a production server you are of course going to set your own DATABASES, but this default value is the best choice for beginners.

  • USE_L10N and LANGUAGE_CODE (see lino.core.site.Site.languages for details on these)

  • LOGGING : See lino.utils.log.configure().

  • The ROOT_URL setting and the files urls.py and polls/views.py generated by Django are not necessary. With Lino you don’t need to worry about URLs and views because Lino defines them for you.

Lino’s settings.py files are small

Lino helps you to keep settings.py files small because it delegates the responsibility of maintaining default values for Django settings to the application developer.

A typical settings.py file for a Lino site consists of a few lines (plus, on a production site, the lines for defining your DATABASES setting). Compare this to a settings.py file generated by Django’s startproject command which contains 120 lines of text (Django version 2.2.7).

>>> from atelier.sheller import Sheller
>>> shell = Sheller()  # will run in a temporary directory
>>> shell("django-admin startproject foo")

>>> shell("wc -l foo/foo/settings.py")
120 foo/foo/settings.py
>>> shell("django-admin --version")  
3.1.7

The Django settings module

The Django settings module is the most important thing in Django. Almost everything you do with Django requires the settings module to be loaded. Django does that automagically as soon as a Python process accesses the settings. And when that moment arrives, Django needs to know the name of your settings module.

You can specify this name either using the DJANGO_SETTINGS_MODULE environment variable or the –settings command-line option of most django-admin commands.

To illustrate what happens when Django doesn’t know the settings module, let’s open a Python session in an environment with Django installed but without any DJANGO_SETTINGS_MODULE environment variable defined, and then type:

>>> from django.conf import settings

This will pass. We said almost everything requires the settings to be loaded. You may import the django.conf.settings module. But as soon as you want to actually access some attribute of this module, you will get an ImproperlyConfigured exception:

>>> print(settings.DEBUG)  
Traceback (most recent call last):
...
django.core.exceptions.ImproperlyConfigured: Requested setting DEBUG, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

A Django settings module must be importable. That is, if DJANGO_SETTINGS_MODULE contains e.g. foo.bar.baz, then Django will do the equivalent of import foo.bar.baz.

Settings packages

We use to speak about “the settings.py file”, but in reality the Django settings module can be in some arbitrary filename. Some Django sites use a layout called a settings package, which is useful when you want to have different variants of settings modules.

In some projects we use a whole package of settings:

  • settings/__init.py : the base for all modules of this package.

  • settings/demo.py : instantiates a SITE variable and thus is designed to be used directly as a DJANGO_SETTINGS_MODULE.

Site-wide default settings

A Lino server configured using getlino : the Lino installer can provide a module with server-wide default settings for this server, and individual sites can decide to import these. Such a module (despite the fact that it is also in a file named settings.py) is not a Django settings module.

Here are some typical Django settings for which a server-wide default value makes sense: ADMINS EMAIL_HOST SERVER_EMAIL DEFAULT_FROM_EMAIL STATIC_ROOT TIME_ZONE

Multilingual Lino sites

The languages setting in the settings.py file of a Lino site specifies what we call the language distribution.

language distribution

The list of languages that are available on a given Lino site.

The language distribution controls two things: (1) the front end languages available on this site and (2) how multilingual database content is stored in your database.

Every site user may choose one of these languages in their user settings.

The server administrator can change the language distribution by specifying the languages setting in the settings.py file.

Lino uses the same language codes as Django.

language code

A code that identifies a language for which screen messages have been translated.

You can see the list of available languages in django/conf/global_settings.py.

You may use any of these languages, but Lino-specific messages are currently being translated only into German, French, Estonian and Dutch. You are welcome to contribute translations to your language of choice. See https://www.lino-framework.org/dev/translate

Having more than one language in your language distribution will make your Lino site multilingual. Changing this setting may change your database structure and thus might require a data migration. This is because this setting also controls how multilingual database content is stored in your database.

Two possibilities to override site attributes

There are two possibilities to override the Site attributes. The most basic way is:

from lino_noi.lib.noi.settings import *
SITE = Site(globals(), title="My Lino site", is_demo_site=False, languages="en fr")
DEBUG = True

The more explicit way is this:

from lino_book.projects.chatter.settings import *

class Site(Site):
    title = "My Lino site"
    is_demo_site = False
    languages = "en fr"

SITE = Site(globals())
DEBUG = True

This way is recommended because it allows to override methods as well. Yes, Lino saves us not only from having to define all-uppercase settings, it also adds the full power of the Python language to your settings.py file.

Summary

Django settings module

A module that is imported by a Python process when it uses Django. It is just a Python module with module-level variables, most of them upper-case. It is usually stored in a file named settings.py.

See https://docs.djangoproject.com/en/5.0/topics/settings/

DJANGO_SETTINGS_MODULE

The environment variable that is expected to contain the Python name of the Django settings module.

settings.py

The conventional name of a file that contains a Django settings module.

Note that a file of this name also can contain Site-wide default settings or the default Site class of a Lino application.

Don’t read

A site feature is a deprecated term. The concept no longer exists.

site feature

Was used to designate a boolean configuration option that can be either enabled or disabled for a given Lino site by its server administrator. It can influence the list of installed plugins.

For example the third_party_authentication setting:

SITE.activate_feature("third_party_authentication")