Skip to content

Instantly share code, notes, and snippets.

@mmalone
Created July 14, 2009 23:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmalone/147312 to your computer and use it in GitHub Desktop.
Save mmalone/147312 to your computer and use it in GitHub Desktop.
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)
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