20130321 (Thursday, 21 March 2013)¶
Storing Site configuration in a singleton database row¶
lino.ui.Site
has a site_config property which
returns the one and only
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 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 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 Django ticket #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
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()