.. _howto.settings:

========================================
Modifying your local :file:`settings.py`
========================================

Every :term:`Lino site` is defined by a :term:`Django settings module`, usually
defined in a file named :xfile:`settings.py`.

A minimal Lino :xfile:`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 :term:`Lino application` into
your local settings module, including a :class:`Site` class, then you
*instantiate* that :class:`Site` class and store the instance in a *variable*
named :setting:`SITE`. Every :term:`Lino site` requires a setting named
:setting:`SITE`.

.. setting:: SITE

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


As a :term:`site maintainer` you can override many settings by modifying the
:xfile:`settings.py` file generated by :cmd:`getlino startsite`.

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

  go mysite
  nano settings.py

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

The :xfile:`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 :xfile:`settings.py` is okay::

  $ python manage.py validate


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 :xfile:`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 ('ledger', 'start_year', 2018)

That is, you override the :meth:`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()
<https://docs.python.org/3/library/functions.html#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 :setting:`INSTALLED_APPS` and
:setting:`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 :xfile:`settings.py`.

Lino does more than this. It will for example read the `__file__
<http://docs.python.org/2/reference/datamodel.html#index-49>`__
attribute of this, to know where your :file:`settings.py` is in the
file system.

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

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

- :setting:`USE_L10N` and :setting:`LANGUAGE_CODE` (see :doc:`/dev/languages`
  for details on these)

- :setting:`LOGGING` : See :func:`lino.utils.log.configure`.

- The :setting:`ROOT_URL` setting and the files :file:`urls.py` and
  :file:`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 :xfile:`settings.py` files are small
===========================================

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

A typical :xfile:`settings.py` file for a Lino site consists of a few lines
(plus, on a production site, the lines for defining your :setting:`DATABASES`
setting). Compare this to a :file:`settings.py` file generated by Django's
:manage:`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")
<BLANKLINE>
>>> shell("wc -l foo/foo/settings.py")
120 foo/foo/settings.py
>>> shell("django-admin --version")  #doctest: -SKIP
3.1.4




.. _settings:

The Django settings module
==========================

The :term:`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 :envvar:`DJANGO_SETTINGS_MODULE`
environment variable or the `--settings` command-line option of most
:term:`django-admin commands <django-admin command>`.

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
:envvar:`DJANGO_SETTINGS_MODULE` environment variable defined, and then type:

.. Make sure that DJANGO_SETTINGS_MODULE isn't set because otherwise Django
   raises another exception:

   >>> import os ; u = os.environ.pop('DJANGO_SETTINGS_MODULE', None)

>>> from django.conf import settings

This will pass. We said *almost* everything requires the settings to be loaded.
You may import the :mod:`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)  #doctest: +IGNORE_EXCEPTION_DETAIL
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
:envvar:`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 :xfile:`settings.py` file", but in reality the
:term:`Django settings module` can be in some arbitrary filename.  Some Django
sites use a layout called a `settings package <Settings packages>`_, which is
useful when you want to have different variants of settings modules.

In some projects we use a whole package of settings:

- :file:`settings/__init.py` : the base for all modules of this
  package.

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


.. _server_wide_settings:

Site-wide default settings
==========================

A :term:`Lino server` configured using :ref:`getlino` 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
:xfile:`settings.py`) is not a :term:`Django settings module`.


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



Summary
=======

.. glossary::

  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 :xfile:`settings.py`.

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

.. envvar:: DJANGO_SETTINGS_MODULE

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

.. xfile:: settings.py

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

  Note that a file of this name also can contain :ref:`server_wide_settings` or
  the :class:`Site` class of an application (:doc:`/dev/site`).