Last active
December 10, 2015 14:38
-
-
Save minism/4448466 to your computer and use it in GitHub Desktop.
Cached method by related model save
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
from django.db.models.signals import post_save | |
from django.db.models.loading import get_model | |
from cachemodel.decorators import cached_method | |
def model2label(obj): | |
return ("%s.%s" % (obj._meta.app_label, obj._meta.object_name)) | |
class CachePublishRegistry(object): | |
""" | |
Tracks dependencies between models/fields for post_save logic. | |
Register a dependency between methods and models with register_relationship() | |
When `model` is saved, we call `model`.`field`.publish_method(`method_to_publish`) | |
""" | |
def __init__(self): | |
self._registry = {} | |
post_save.connect(self.publish_relationships) | |
def publish_relationships(self, sender, instance, created, **kwargs): | |
model_label = model2label(sender) | |
if model_label in self._registry: | |
for reverse_field, method_to_publish, created_only in self._registry[model_label]: | |
if created_only and not created: | |
continue | |
for arg in reverse_field.split('.'): | |
instance = getattr(instance, arg) | |
reverse_object = instance | |
reverse_object.publish_method(method_to_publish) | |
print "Publishing %s.%s.%s" % (model_label, reverse_field, method_to_publish) | |
def register_relationship(self, model_label, reverse_field, method_to_publish, created_only=False): | |
if not isinstance(model_label, basestring) and issubclass(model_label, models.Model): | |
model_label = model2label(model_label) | |
self._registry[model_label] = self._registry.get(model_label, []) | |
self._registry[model_label].append((reverse_field, method_to_publish, created_only)) | |
registry = CachePublishRegistry() | |
def cached_by_relationship(related_model, reverse_field, created_only=False): | |
def decorator(target): | |
# Use the original cached_method decorator but disable auto publish | |
wrapper = cached_method(auto_publish=False)(target) | |
# Register the relationship to generate on save logic | |
registry.register_relationship(related_model, reverse_field, target.__name__, created_only=created_only) | |
return wrapper | |
return decorator | |
### Usage: blog/models.py | |
class Post(models.Model): | |
body = models.CharField() | |
@cached_by_relationship('blog.Comment', 'post', created_only=True) | |
def comment_count(): | |
return self.comment_set.count() | |
class Comment(models.Model): | |
body = models.CharField() | |
post = models.ForeignKey(post) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment