================================== 20130321 (Thursday, 21 March 2013) ================================== Storing Site configuration in a singleton database row ------------------------------------------------------ :class:`lino.ui.Site` has a `site_config` property which returns the *one and only* :class:`SiteConfig ` instance. One might call it a "singleton database row". The concept includes some challenges, has caused me quite some work in the past and todays whole workday. Some fragments on how it is implemented. The `site_config` property on the :class:`lino.ui.Site` class uses a cached object instance:: @property def site_config(self): if self._site_config is None: SiteConfig = self.modules.ui.SiteConfig try: self._site_config = SiteConfig.objects.get(pk=1) except SiteConfig.DoesNotExist: kw = dict(pk=1) kw.update(self.site_config_defaults) self._site_config = SiteConfig(**kw) return self._site_config One complication is that we must clear this cached instance at certain moments:: def clear_site_config(self): self._site_config = None But when to call this method? There is unfortunately no single clear signal to which to connect it. That's why we connect it to all the following signals:: def my_callback(sender,**kw): settings.SITE.clear_site_config() from django.db.backends.signals import connection_created connection_created.connect(my_callback) testcase_setup.connect(my_callback) models.signals.post_syncdb.connect(my_callback) models.signals.post_save.connect(my_callback,sender=SiteConfig) # NOTE The testcase_setup signal is my own custom signal, emitted only by djangoutils.utils.test.TestCase. NOTE : I didn't manage to get that last line working. When specifying a `sender`, the signal seems to just not get sent. Worked around this by overriding SiteConfig.save() to call directly clear_site_config() Another complication is that we must write a `custom manager `_: Can't we avoid all these complications by not caching the object at all? One of the things I tried yesterday was something like this:: @property def site_config(self): SiteConfig = self.modules.ui.SiteConfig try: return SiteConfig.objects.get(pk=1) except SiteConfig.DoesNotExist: kw = dict(pk=1) kw.update(self.site_config_defaults) sc = SiteConfig(**kw) sc.full_clean() sc.save() return sc But this caused code as the following (in :mod:`lino_welfare.pcsw.modlib.tests.pcsw_tests`) to produce unexpected results:: def test00(self): sc = settings.SITE.site_config sc.signer1 = Person(first_name="Ernst",last_name="Keutgen") ; sc.signer1.save() sc.signer2 = Person(first_name="Johann",last_name="Ossemann") ; sc.signer2.save() sc.full_clean() ; sc.save() Because saving a Person itself causes an update of the SiteConfig record (to increment the next_partner_id BTW I also stumbled over Django ticket :djangoticket:`10200` (loaddata command does not raise CommandError on errors). These problems seem now solved. Just the pcsw_demo_tests and pcsw_sql_tests are still deactivated, waiting for adaptation. That doesn't stop me from checking it in. TODO ---- Yes, there is much to do: - Write unit tests for the new features in :mod:`lino_welfare.modlib.jobs` - rename users.UserGroups to auth.PermissionGroups - implement new user requests for `welfare.debts`. - start translating the `welfare.userman`, using http://sphinx-doc.org/intl.html - Use python-babel for generating the message files. http://jinja.pocoo.org/docs/integration/#babel-integration - Explore and use python-babel's interface to the CLDR (Common Locale Data Repository). See http://babel.edgewall.org/wiki/Documentation/intro.html#locale-data - Find a solution to handle the current situation: version numbers are already incremented to the new ones, release notes are started, but the thing isn't yet officially released. I don't want to edit four files and rebuild the whole html docs . to change this sentence User requests for `welfare.debts` -------------------------------------- - The Reference field of an Account wasn't visible - add_site_attribute()