diff --git a/django_proxy/models.py b/django_proxy/models.py index 49da5bb..815f48f 100644 --- a/django_proxy/models.py +++ b/django_proxy/models.py @@ -4,14 +4,16 @@ from datetime import datetime from django_proxy.managers import PublicManager + class ProxyBase(models.Model): - '''Represents the proxy objects. Retains the name, description, - and any tags related to the associated object. - + """ + Represents the proxy objects. Retains the name, description, and any tags + related to the associated object. + A good use, I've found, for this type of object is aggregate view of all content types in an RSS feed (post, links, tweets, etc.). - - ''' + + """ content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey() @@ -21,19 +23,19 @@ class ProxyBase(models.Model): description = models.TextField(blank=True, null=True) tags = models.CharField(max_length=255, blank=True, null=True) pub_date = models.DateTimeField(default=datetime.now) - + #audit fields created_on = models.DateTimeField(default=datetime.now) updated_on = models.DateTimeField(default=datetime.now) - + objects = PublicManager() - + def __unicode__(self): return '%s' % self.title - + class Meta: abstract = True - + def save(self, *args, **kwargs): self.updated_on = datetime.now() super(ProxyBase, self).save(*args, **kwargs) diff --git a/django_proxy/signals.py b/django_proxy/signals.py index 66ab013..def1f32 100644 --- a/django_proxy/signals.py +++ b/django_proxy/signals.py @@ -1,105 +1,134 @@ +import datetime + from django.db.models import get_model from django.contrib.contenttypes.models import ContentType -def proxy_save(sender, **kwargs): - ''' Handles the save/update of a Proxy instance. ''' - instance = kwargs['instance'] - created = kwargs['created'] +class DjangoProxy(object): + instance = None + object = None + proxy_model = None - cls = instance.ProxyMeta - model_str = getattr(cls, 'model_str', 'django_proxy.proxy') - model = get_model(*model_str.split('.')) - obj = model() - active = False + _required_fields = ['title', 'description'] + _field_mappings = [ + ('title', None), + ('description', None), + ('pub_date', datetime.datetime.now()), + ('tags', None), + ] - if created: - obj.content_object = instance - else: - try: - ctype = ContentType.objects.get_for_model(instance) - obj = model._default_manager.get(object_id=instance.id, content_type=ctype) - except model.DoesNotExist: - obj = model() - obj.content_object = instance - - if hasattr(cls, 'active'): - if isinstance(cls.active, basestring): - active_field = getattr(instance, cls.active, None) - if callable(active_field): - active = active_field() - else: - active = active_field + def __init__(self, instance, created=None): + self.instance = instance + self.proxy_model = instance.ProxyMeta + + model = self._get_proxy_model(instance) + self.object = model() + + if created: + self.object.content_object = instance else: try: - active_field = cls.active - objfield = active_field.keys()[0] - active_status = active_field.values()[0] - actual_status = getattr(instance, objfield, None) - if active_status == actual_status: - active = True - except Exception: - # deal with this better... - pass - else: - active = True - - if not active and obj.id: - obj.delete() - return - - if hasattr(cls, 'title'): - title = getattr(instance, cls.title, None) - if callable(title): - obj.title = title() - else: - obj.title = title - else: - raise Exception('Missing title field') - - if hasattr(cls, 'description'): - description = getattr(instance, cls.description, None) - if callable(description): - obj.description = description() - else: - obj.description = description - else: - raise Exception('Missing description field') - - #proxy pub_date isn't required so confirm - if hasattr(cls, 'pub_date'): - pub_date = getattr(instance, cls.pub_date, None) - if callable(pub_date): - obj.pub_date = pub_date() + ctype = ContentType.objects.get_for_model(instance) + self.object = model._default_manager.get(object_id=instance.id, content_type=ctype) + except model.DoesNotExist: + self.object = model() + self.object.content_object = instance + + def _get_attr(self, attr, obj): + if hasattr(self.proxy_model, attr): + value = getattr(self.instance, getattr(obj, attr)) + if callable(value): + return value() + else: + return value + + def _get_proxy_model(self, instance): + model_str = getattr(instance.ProxyMeta, 'model_str', 'django_proxy.proxy') + model = get_model(*model_str.split('.')) + return model + + def _valdiate(self): + missing = [] + for field in self._required_fields: + if not getattr(self.proxy_model, field, None): + missing.append(field) + if len(missing): + raise ValueError('Missing required fields: %s' % (', '.join(missing))) + + def create(self): + self._valdiate() + active = self.get_active() + object = self.object + + if active: + for mapping in self._field_mappings: + setattr(object, mapping[0], self._get_attr(mapping[0], self.proxy_model) or mapping[1]) + object.active = active + object.save() + + elif object.id: + object.delete() + + def delete(self): + """ + Remove any remaining child/associated Proxy records. + + """ + model = self._get_proxy_model(self.instance) + ctype = ContentType.objects.get_for_model(self.instance) + try: + self.object = model._default_manager.get(object_id=self.instance.id, content_type=ctype) + self.object.delete() + except model.DoesNotExist: + pass + + def get_active(self): + active = False + if hasattr(self.proxy_model, 'active'): + if isinstance(self.proxy_model.active, basestring): + active_field = getattr(self.instance, self.proxy_model.active) + if callable(active_field): + active = active_field() + else: + active = active_field + + elif isinstance(self.proxy_model.active, dict): + try: + active_field = self.proxy_model.active + objfield = active_field.keys()[0] + active_status = active_field.values()[0] + actual_status = getattr(self.instance, objfield) + if active_status == actual_status: + active = True + + except Exception: + pass else: - obj.pub_date = pub_date + active = True - #proxy tag isn't require so confirm - if hasattr(cls, 'tags'): - tags = getattr(instance, cls.tags, None) - if callable(tags): - obj.tags = tags() - else: - obj.tags = tags + return active - if active: - obj.save() + +def proxy_save(sender, **kwargs): + """ + Handles the save/update of a Proxy instance. + + """ + instance = kwargs['instance'] + created = kwargs['created'] + + dp = DjangoProxy(instance, created) + dp.create() def proxy_delete(sender, **kwargs): - '''Responsible for handling the deletion of any child/associated Proxy records. + """ + Responsible for handling the deletion of any child/associated Proxy records. Coupled to associated object's post_delete signal. - ''' + """ instance = kwargs['instance'] - ctype = ContentType.objects.get_for_model(instance) - - cls = instance.ProxyMeta - model_str = getattr(cls, 'model_str', 'django_proxy.proxy') - model = get_model(*model_str.split('.')) - try: - obj = model._default_manager.get(object_id=instance.id, content_type=ctype) - obj.delete() - except model.DoesNotExist: - pass + + dp = DjangoProxy(instance) + dp.delete()