Home > Programming, Python > Lazy objects in Django

Lazy objects in Django

Working on one of my Django projects, I created a new context processor to populate some template context variables.  One of them was a list of values pulled from the database that was only used on a few pages, so I tried to wrap it in a SimpleLazyObject:

from django.utils.functional import SimpleLazyObject
def current_presentation(request):
    presentation = SimpleLazyObject(lambda: fetch_current_presentation(request.user))
    presentation_records = SimpleLazyObject(lambda: list(presentation.items.values_list('record_id', flat=True).distinct()))
    return {
     'current_presentation': presentation,
     'current_presentation_records': presentation_records,
    }

That unfortunately does not work:

django.template.TemplateSyntaxError
TemplateSyntaxError: Caught TypeError while rendering: argument of type 'SimpleLazyObject' is not iterable

The problem is that the SimpleLazyObject wrapper does not implement an __iter__ method, so a wrapped object that is iterable loses that property.

The fix: a new subclass of SimpleLazyObject:

class IterableLazyObject(SimpleLazyObject):
    def __iter__(self):
        if self._wrapped is None: self._setup()
        return self._wrapped.__iter__()

Done!

Advertisements
Categories: Programming, Python Tags:
  1. July 24, 2012 at 4:10 pm

    To lazy-load the object only when iteration begins, this may be better:

    if self._wrapped is empty:
        self._setup()
    for thing in self._wrapped:
        yield thing
    
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: