Introducing the Site class

As explained in Lino and your Django settings and The Lino Polls tutorial, Lino expects a variable named SITE in your Django settings module, and this variable must contain an instance of the Site class .

The Site is the base class for representing a "Lino application". This concept brings an additional level of encapsulation to Django. If you knew Django before Lino, you might imagine the Site class as a kind of a "project template". Read What is an application? if you wonder why we chose that name.

A Site has attributes like Site.verbose_name (the "short" user-visible name) and the Site.version which are used by the method Site.welcome_text(). It also defines a Site.startup() method and signals which fire when the application starts up.

The base Site class is designed to be subclassed by the application developer, then imported into a local settings.py, where a local system administrator may subclass it another time.

A Lino application starts to "live" when such a Site class gets instantiated. This instance of your application is stored in the SITE variable of a local settings.py.

Django settings usually contain simple values (strings, integers, or lists or dictionaries thereof). But Lino's SITE setting contains a Python object which has methods that can be called by application code at runtime.

Instantiating a Site

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. To be precise, here are these settings:

>>> from lino_book.projects.docs.settings import Site
>>> pseudoglobals = {}
>>> SITE = Site(pseudoglobals)
>>> sorted(pseudoglobals.keys())
... 
['AUTHENTICATION_BACKENDS', 'AUTH_USER_MODEL', 'DATABASES', 'FIXTURE_DIRS', 'INSTALLED_APPS', 'LANGUAGES', 'LANGUAGE_CODE', 'LOCALE_PATHS', 'LOGIN_REDIRECT_URL', 'LOGIN_URL', 'LOGOUT_REDIRECT_URL', 'MEDIA_ROOT', 'MEDIA_URL', 'MIDDLEWARE', 'ROOT_URLCONF', 'SERIALIZATION_MODULES', 'STATICFILES_DIRS', 'STATIC_ROOT', 'STATIC_URL', 'TEMPLATES', 'USE_L10N']

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.

How Lino builds the INSTALLED_APPS setting

A Site is usually meant to work for a given set of Django apps (i.e. what's in the INSTALLED_APPS setting). It is a collection of apps which make up a whole. To define this collection, the application developper usually overrides the Site.get_installed_apps() method.

Lino calls the get_installed_apps method which it expects to yield a list of strings. Lino then adds some more "system" apps and stores the resulting list into your INSTALLED_APPS setting.

Other settings

Other Django setting for which Lino sets default values are:

  • 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 what we think the best choice for beginners.

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

  • More documentation about the LOGGING setting in 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.

Additional local apps

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

>>> from lino_book.projects.docs.settings import Site
>>> pseudoglobals = {}
>>> Site(pseudoglobals, "lino_xl.lib.events")  
<lino_book.projects.docs.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
django.contrib.contenttypes
lino.modlib.gfks
lino.modlib.changes
lino.modlib.memo
lino.modlib.notify
lino.modlib.languages
lino.modlib.office
lino_xl.lib.xl
lino_xl.lib.countries
lino_xl.lib.contacts
lino.modlib.uploads
lino_xl.lib.polls
lino_xl.lib.concepts
lino.modlib.tinymce
lino.modlib.export_excel
lino_xl.lib.events
django.contrib.sessions

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

Besides this you can override any class argument using a keyword argment of same name:

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.

Technical details

Here are the Django settings that Lino will override:

>>> from lino.core.site import TestSite as Site
>>> SITE = Site()
>>> print([k for k in SITE.django_settings.keys() if k.isupper()])
... 
['SECRET_KEY', 'DATABASES', 'SERIALIZATION_MODULES', 'LANGUAGES',
'INSTALLED_APPS', 'MEDIA_ROOT', 'ROOT_URLCONF', 'MEDIA_URL', 'STATIC_ROOT',
'STATIC_URL', 'TEMPLATES', 'MIDDLEWARE', 'AUTHENTICATION_BACKENDS', 'LOGIN_URL',
'LOGIN_REDIRECT_URL', 'LOGOUT_REDIRECT_URL', 'FIXTURE_DIRS', 'LOCALE_PATHS',
'STATICFILES_DIRS']
>>> from pprint import pprint
>>> from atelier.utils import rmu
>>> pprint(rmu(SITE.django_settings))
... 
{'AUTHENTICATION_BACKENDS': ['lino.core.auth.backends.ModelBackend'],
 'DATABASES': {'default': {'ENGINE': 'django.db.backends.sqlite3',
                           'NAME': Path('.../core/default.db')}},
 'FIXTURE_DIRS': (),
 'INSTALLED_APPS': ('lino',
                    'django.contrib.staticfiles',
                    'lino.modlib.about',
                    'lino.modlib.jinja',
                    'lino.modlib.bootstrap3',
                    'lino.modlib.extjs'),
 'LANGUAGES': [],
 'LOCALE_PATHS': (),
 'LOGIN_REDIRECT_URL': '/',
 'LOGIN_URL': '/accounts/login/',
 'LOGOUT_REDIRECT_URL': None,
 'MEDIA_ROOT': Path('.../core/media'),
 'MEDIA_URL': '/media/',
 'MIDDLEWARE': ('django.middleware.common.CommonMiddleware',
                        'lino.core.auth.middleware.NoUserMiddleware',
                        'lino.utils.ajax.AjaxExceptionResponse'),
 'ROOT_URLCONF': 'lino.core.urls',
 'SECRET_KEY': '20227',
 'SERIALIZATION_MODULES': {'py': 'lino.utils.dpy'},
 'STATICFILES_DIRS': (),
 'STATIC_ROOT': Path('...static'),
 'STATIC_URL': '/static/',
 'TEMPLATES': [{'APP_DIRS': True,
                'BACKEND': 'django.template.backends.django.DjangoTemplates',
                'DIRS': [],
                'OPTIONS': {'context_processors': ['django.template.context_processors.debug',
                                                   'django.template.context_processors.i18n',
                                                   'django.template.context_processors.media',
                                                   'django.template.context_processors.static',
                                                   'django.template.context_processors.tz',
                                                   'django.contrib.messages.context_processors.messages']}},
               {'BACKEND': 'django.template.backends.jinja2.Jinja2',
                'DIRS': [],
                'OPTIONS': {'environment': 'lino.modlib.jinja.get_environment'}}],
 '__file__': '.../lino/core/site.py...'}

Here are the Django settings which Lino does not modify:

>>> import lino_book.projects.lydia.settings.demo as settings
>>> print([s for s in dir(settings)
...     if not s in SITE.django_settings and s[0].isupper()])
... 
['ADMINS', 'ALLOWED_HOSTS', 'AUTH_USER_MODEL', 'DEBUG',
'DEBUG_PROPAGATE_EXCEPTIONS', 'EMAIL_HOST', 'LANGUAGE_CODE', 'MANAGERS',
'SETUP_INFO', 'SITE', 'Site', 'TEMPLATE_DEBUG', 'TEST_RUNNER', 'TIM2LINO_LOCAL',
'TIM2LINO_USERNAME', 'TIME_ZONE', 'USE_I18N', 'USE_L10N', 'USE_TZ']