Skip to content Skip to sidebar Skip to footer

How To Avoid Import-time Database Access In Django?

My Django app has a number of categories for things which I store in a Category model. I reference these frequently in code, and so I've found it useful to have a module with refer

Solution 1:

I've run into the same issue myself, and agree that it would be great to have some best practices here.

I ended up with an approach based on the descriptor protocol:

classLazyInstance:
    def__init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        self.instance = Nonedef__get__(self, obj, cls):
        if self.instance isNone:
            self.instance, _ = cls.objects.get_or_create(*self.args, **self.kwargs)

        return self.instance

Then in my model classes I have some special objects:

classCategory(models.Model):
    name = models.CharField()

    DOGS = LazyInstance(name="dogs")
    CATS = LazyInstance(name="cats")

So nothing happens at import time. The first time the special object is accessed, the relevant instance is looked up (and created, if necessary) and cached.

Solution 2:

There's not much you can do with module-level variables, since you cannot override their access functions. However you can do that for class and instance variables via __getattribute__. You can use that to load your categories lazily:

classCategories(object):
    _categories = {'DOGS': 'dogs', 'CATS': 'cats'}
    def__getattribute__(self, key):
        try:
            returnsuper(Categories, self).__getattribute__(key)
        except AttributeError:
            passtry:
            value = load_category(self._categories[key])
        except KeyError:
            raise AttributeError(key)
        setattr(self, key, value)
        return value

Categories = Categories()  # Shadow class with singleton instance

Instead of module.DOGS you would then use module.Categories.DOGS. Upon the first access the category is loaded and stored for future lookups.

Solution 3:

I've used lazy_object_proxy (wich works with passed function but without passed arguments) in companion with functools.partial like below:

import lazy_object_proxy
from functools import partial

defload_category(name):
  # prepare an argument-less runnable function
  loader = partial(Category.objects.get, name)

  # pass the function to the proxyreturn lazy_object_proxy.Proxy(loader)

DOGS = load_category("dogs")
CATS = load_category("cats")

Post a Comment for "How To Avoid Import-time Database Access In Django?"