X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/aca27b0d4429d193b539f993eb629d28efd2157b..855ec6e1d29382dcbbfa63aece9e3b127b8ecf11:/models/base.py diff --git a/models/base.py b/models/base.py index 37710b8..27c45dc 100644 --- a/models/base.py +++ b/models/base.py @@ -3,7 +3,9 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic from django.utils import simplejson as json from django.core.exceptions import ObjectDoesNotExist +from philo.exceptions import AncestorDoesNotExist from philo.utils import ContentTypeRegistryLimiter +from philo.signals import entity_class_prepared from UserDict import DictMixin @@ -52,6 +54,7 @@ class Attribute(models.Model): class Meta: app_label = 'philo' + unique_together = ('key', 'entity_content_type', 'entity_object_id') value_content_type_limiter = ContentTypeRegistryLimiter() @@ -71,8 +74,8 @@ class Relationship(models.Model): entity_object_id = models.PositiveIntegerField(verbose_name='Entity ID') entity = generic.GenericForeignKey('entity_content_type', 'entity_object_id') key = models.CharField(max_length=255) - value_content_type = models.ForeignKey(ContentType, related_name='relationship_value_set', limit_choices_to=value_content_type_limiter, verbose_name='Value type') - value_object_id = models.PositiveIntegerField(verbose_name='Value ID') + value_content_type = models.ForeignKey(ContentType, related_name='relationship_value_set', limit_choices_to=value_content_type_limiter, verbose_name='Value type', null=True, blank=True) + value_object_id = models.PositiveIntegerField(verbose_name='Value ID', null=True, blank=True) value = generic.GenericForeignKey('value_content_type', 'value_object_id') def __unicode__(self): @@ -80,6 +83,7 @@ class Relationship(models.Model): class Meta: app_label = 'philo' + unique_together = ('key', 'entity_content_type', 'entity_object_id') class QuerySetMapper(object, DictMixin): @@ -102,7 +106,30 @@ class QuerySetMapper(object, DictMixin): return list(keys) +class EntityOptions(object): + def __init__(self, options): + if options is not None: + for key, value in options.__dict__.items(): + setattr(self, key, value) + if not hasattr(self, 'proxy_fields'): + self.proxy_fields = [] + + def add_proxy_field(self, proxy_field): + self.proxy_fields.append(proxy_field) + + +class EntityBase(models.base.ModelBase): + def __new__(cls, name, bases, attrs): + new = super(EntityBase, cls).__new__(cls, name, bases, attrs) + entity_options = attrs.pop('EntityMeta', None) + setattr(new, '_entity_meta', EntityOptions(entity_options)) + entity_class_prepared.send(sender=new) + return new + + class Entity(models.Model): + __metaclass__ = EntityBase + attribute_set = generic.GenericRelation(Attribute, content_type_field='entity_content_type', object_id_field='entity_object_id') relationship_set = generic.GenericRelation(Relationship, content_type_field='entity_content_type', object_id_field='entity_object_id') @@ -214,7 +241,7 @@ class TreeManager(models.Manager): class TreeModel(models.Model): objects = TreeManager() parent = models.ForeignKey('self', related_name='children', null=True, blank=True) - slug = models.SlugField() + slug = models.SlugField(max_length=255) def has_ancestor(self, ancestor): parent = self @@ -225,7 +252,9 @@ class TreeModel(models.Model): return False def get_path(self, root=None, pathsep='/', field='slug'): - if root is not None and self.has_ancestor(root): + if root is not None: + if not self.has_ancestor(root): + raise AncestorDoesNotExist(root) path = '' parent = self while parent and parent != root: @@ -249,7 +278,7 @@ class TreeModel(models.Model): abstract = True -class TreeEntity(TreeModel, Entity): +class TreeEntity(Entity, TreeModel): @property def attributes(self): if self.parent: