One of my favorite patterns in Django is the combination of “fat” models and
Fat models are a general MVC concept which encourages pushing logic into methods on your Model layer rather than the Controller (“view” in Django parlance). This has a lot of benefits. It helps maintain the DRY (Don’t Repeat Yourself) principle by making common logic easy to find/reuse and makes it easy to break the logic down into small testable units.
One problem with this approach is that as you break down your logic into smaller more reusable units, you may find yourself using them multiple times within a single response. If your methods are particularly resource intensive, it will become an unnecessary performance hit. A common place you find this is in Django templates with patterns like this:
This will call the
top_ten_reviews method twice. If that method is making database calls, you’ve now doubled them.
cached_property. This decorator will cache the results of a method for the duration of the request and return it as a property when called again. This technique is known as memoization. Let’s look at a simple example:
In my code, I can lookup an
Item object and reference the property
item.top_ten_reviews. The first reference will build the queryset, but future references will not, instead recalling the queryset from an in-memory cache.
A couple caveats to
- Like Python’s built-in
property, it only works for methods without an argument (other than
- It may not be thread-safe. If the object’s data isn’t changing between threads, it’s likely safe. If you are using threads, look to the cached-property module for a thread-safe implemenation.
cached_property is one of my favorite “easy wins” when working on un-optimized code. It’s a quick and relatively safe way to cut out repeated slow tasks without getting into full-blown caching and the ensuing invalidation challenges.