Created
July 14, 2009 23:10
-
-
Save mmalone/147312 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
class AssetTagDescriptor(object): | |
""" | |
A descriptor which provides access to an asset's tags. | |
""" | |
pre_save_manager_name = '__asset_tag_pre_save_manager_descriptor' | |
def __get__(self, instance, cls=None): | |
if not instance: | |
raise AttributeError('Manager must be accessed via instance') | |
from app.models import Tag | |
if instance.id is not None: | |
# The asset has been saved, return a normal DB manager | |
class AssetTagManager(models.Manager): | |
def get_query_set(self): | |
return Tag.objects.filter(assettag__asset=instance) | |
def add(self, *objs): | |
from app.models import AssetTag | |
for obj in objs: | |
if isinstance(obj, basestring): | |
obj, created = Tag.objects.get_or_create(tag=obj) | |
try: | |
AssetTag.objects.create(asset=instance, tag=obj, group=instance.group) | |
except IntegrityError: | |
pass # tag already exists for this asset. | |
def remove(self, *objs): | |
from app.models import AssetTag | |
for obj in objs: | |
try: | |
if isinstance(obj, basestring): | |
obj = Tag.objects.get(tag=obj) | |
AssetTag.objects.get(asset=instance, tag=obj, group=instance.group).delete() | |
except ObjectDoesNotExist: | |
pass | |
def clear(self): | |
for tag in self.get_query_set().all(): | |
self.remove(tag) | |
return AssetTagManager() | |
else: | |
# The asset hasn't been saved, fake it. | |
if not hasattr(instance, self.pre_save_manager_name): | |
class AssetTagManager(models.Manager): | |
def __init__(self): | |
self.tags = set() | |
def all(self): | |
return self.tags | |
def add(self, *objs): | |
for obj in objs: | |
if isinstance(obj, basestring): | |
obj, created = Tag.objects.get_or_create(tag=obj) | |
self.tags.add(obj) | |
def remove(self, *objs): | |
for obj in objs: | |
try: | |
if isinstance(obj, basestring): | |
obj = Tag.objects.get(tag=obj) | |
self.tags.remove(obj) | |
except (ValueError, ObjectDoesNotExist): | |
pass | |
def clear(self): | |
for tag in self.tags.copy(): | |
self.remove(tag) | |
setattr(instance, self.pre_save_manager_name, AssetTagManager()) | |
return getattr(instance, self.pre_save_manager_name) | |
def __set__(self, instance, value): | |
if instance is None: | |
raise AttributeError("Manager must be accessed via instance") | |
manager = self.__get__(instance) | |
manager.clear() | |
manager.add(*value) |
This file contains hidden or 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 app import managers | |
class Asset(models.Model): | |
name = models.CharField(_('name'), max_length=255) | |
tags = managers.AssetTagDescriptor() | |
class Tag(models.Model): | |
tag = models.CharField(_('tag'), max_length=64, unique=True) | |
class AssetTag(models.Model): | |
tag = models.ForeignKey(Tag) | |
asset = models.ForeignKey(Asset) | |
def save_asset_tags(sender, instance, created, **kwargs): | |
if created and hasattr(instance, managers.AssetTagDescriptor.pre_save_manager_name): | |
for tag in getattr(instance, managers.AssetTagDescriptor.pre_save_manager_name).all(): | |
AssetTag.objects.create(asset=instance, tag=tag) | |
signals.post_save.connect(save_asset_tags, sender=Asset, dispatch_uid=save_asset_tags.__name__) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment