.. highlight:: ini Storing Config in DB ==================== We're getting ahead of ourselves a little here, if you're reading this manual straight through. But for reference sake this probably belongs here. Settings Table -------------- If you already have a Rattail DB, then it has a table named ``setting`` which is designed to store config values. It's just a regular table so you can write settings via SQL if you like: .. code-block:: sql insert into setting (name, value) values ('rattail.app_title', 'Poser'); update setting set value = 'Something Else' where name = 'rattail.app_title'; Although the main reason for putting settings in the DB is usually so you can edit them via the web app. Telling App to Read Config from DB ---------------------------------- Well first of all we must assume that the DB connection itself is configured. More on that later but let's say you have this in place:: [rattail.db] default.url = postgresql://user:password@localhost/poser Then you also must tell the Rattail config engine that a) it should read config values from the DB at all, but probably also b) it should *prefer* values from the DB over what was read from file. Do this within your config file:: [rattail.config] usedb = true preferdb = true With this in place, when the app requests a config value, it will come from the DB if present, falling back to the file value if that exists. File vs. DB Setting Names ------------------------- You may have noticed that the SQL examples above, and the examples used in :doc:`syntax` are really for the same ``app_title`` setting, but there is a key difference in naming. So in a config file you might have this snippet to define a setting:: [rattail] app_title = Poser But then that same setting is written in SQL as: .. code-block:: sql insert into setting (name, value) values ('rattail.app_title', 'Poser'); In other words the "section" and "option" names from the config file, are joined together with a dot, for the DB setting name. When the app requests a config value, it must specify both a section and option. The config engine then will auto-join them as needed when doing DB lookups. .. code-block:: python config.get('rattail', 'app_title') Avoiding the DB --------------- The app can request config from "file only" if it needs to. It just has to specify a flag when reading the value, for example: .. code-block:: python config.get('rattail', 'app_title', usedb=False) DB Settings Cache ----------------- .. warning:: Unfortunately at this time the caching mechanisms described below are **not reliable**. Docs remain in place for now, but it is very much *not recommended* to enable caching. One downside of reading config values from the DB settings table, is the number of queries involved, as each call to ``config.get()`` would normally involve a separate SQL query. (Not only that, but unless a DB session is passed to ``config.get()`` a new one will be made just for the query.) To help with this, you can enable caching for the DB settings. This should "just work" as expected; i.e. calls to ``config.get()`` need not change. (Although there's no point in passing a DB session when caching is enabled.) To turn on the caching, add to your config file:: [rattail.config] beaker_cache.enabled = true By default this cache will be file-based, storage for which is at e.g. ``/srv/envs/poser/app/cache/config/`` although you can override the paths if you prefer:: [rattail.config] beaker_cache.enabled = true beaker_cache.data_dir = /somewhere/else/data beaker_cache.lock_dir = /somewhere/else/lock Note that by default there is *no expiration* for the cache values, meaning once a particular setting is cached, that value will never expire, and therefore the setting will never be re-fetched from DB (unless a new value is written for it, in which case the cache is invalidated for that setting, which causes a re-fetch next time it's requested). You may want values to expire after say, an hour, so that settings will periodically be re-fetched regardless of write activity. Do that by specifying the number of seconds after which values should expire:: [rattail.config] # nb. expire values after 1 hour beaker_cache.expire = 3600 memcached ========= If you're not crazy about caching to disk and would prefer to use `memcached`_ as the backend instead, first install that: .. _memcached: https://www.memcached.org/ .. code-block:: sh sudo apt install memcached Then install the Python dependencies to your virtual environment: .. code-block:: sh cd /srv/envs/poser source bin/activate pip install 'rattail[memcached]' And finally add to your config file:: [rattail.config] beaker_cache.enabled = true beaker_cache.type = ext:memcached beaker_cache.url = 127.0.0.1:11211 Rattail will try to come up with a unique namespace to use for the cache; this is needed in situations where the same ``memcached`` service is handling multiple "separate" Rattail apps. You can also explicitly set the namespace to use, e.g.:: [rattail.config] beaker_cache.namespace = my_custom_namespace