Added filter_horizontal on blogentry tags. Made minor corrections to BlogView's get_e...
[philo.git] / models / fields.py
1 from django.db import models
2 from django import forms
3 from django.core.exceptions import FieldError
4 from django.utils.text import capfirst
5 from philo.models.base import Entity
6 from philo.signals import entity_class_prepared
7
8
9 __all__ = ('AttributeField', 'RelationshipField')
10
11
12 class EntityProxyField(object):
13         descriptor_class = None
14         
15         def __init__(self, *args, **kwargs):
16                 if self.descriptor_class is None:
17                         raise NotImplementedError('EntityProxyField subclasses must specify a descriptor_class.')
18                 self.verbose_name = kwargs.get('verbose_name', None)
19                 self.help_text = kwargs.get('help_text', None)
20         
21         def actually_contribute_to_class(self, sender, **kwargs):
22                 sender._entity_meta.add_proxy_field(self)
23                 setattr(sender, self.attname, self.descriptor_class(self))
24         
25         def contribute_to_class(self, cls, name):
26                 if issubclass(cls, Entity):
27                         self.name = name
28                         self.attname = name
29                         if self.verbose_name is None and name:
30                                 self.verbose_name = name.replace('_', ' ')
31                         entity_class_prepared.connect(self.actually_contribute_to_class, sender=cls)
32                 else:
33                         raise FieldError('%s instances can only be declared on Entity subclasses.' % self.__class__.__name__)
34         
35         def formfield(self, *args, **kwargs):
36                 raise NotImplementedError('EntityProxyField subclasses must implement a formfield method.')
37         
38         def value_from_object(self, obj):
39                 return getattr(obj, self.attname)
40
41
42 class AttributeFieldDescriptor(object):
43         def __init__(self, field):
44                 self.field = field
45         
46         def __get__(self, instance, owner):
47                 if instance:
48                         if self.field.key in instance._added_attribute_registry:
49                                 return instance._added_attribute_registry[self.field.key]
50                         if self.field.key in instance._removed_attribute_registry:
51                                 return None
52                         try:
53                                 return instance.attributes[self.field.key]
54                         except KeyError:
55                                 return None
56                 else:
57                         raise AttributeError('The \'%s\' attribute can only be accessed from %s instances.' % (self.field.name, owner.__name__))
58         
59         def __set__(self, instance, value):
60                 if self.field.key in instance._removed_attribute_registry:
61                         instance._removed_attribute_registry.remove(self.field.key)
62                 instance._added_attribute_registry[self.field.key] = value
63         
64         def __delete__(self, instance):
65                 if self.field.key in instance._added_attribute_registry:
66                         del instance._added_attribute_registry[self.field.key]
67                 instance._removed_attribute_registry.append(self.field.key)
68
69
70 class AttributeField(EntityProxyField):
71         descriptor_class = AttributeFieldDescriptor
72         
73         def __init__(self, field_template=None, key=None, **kwargs):
74                 super(AttributeField, self).__init__(**kwargs)
75                 self.key = key
76                 if field_template is None:
77                         field_template = models.CharField(max_length=255)
78                 self.field_template = field_template
79         
80         def contribute_to_class(self, cls, name):
81                 super(AttributeField, self).contribute_to_class(cls, name)
82                 if self.key is None:
83                         self.key = name
84         
85         def formfield(self, **kwargs):
86                 defaults = {'required': False, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
87                 defaults.update(kwargs)
88                 return self.field_template.formfield(**defaults)
89
90
91 class RelationshipFieldDescriptor(object):
92         def __init__(self, field):
93                 self.field = field
94         
95         def __get__(self, instance, owner):
96                 if instance:
97                         if self.field.key in instance._added_relationship_registry:
98                                 return instance._added_relationship_registry[self.field.key]
99                         if self.field.key in instance._removed_relationship_registry:
100                                 return None
101                         try:
102                                 return instance.relationships[self.field.key]
103                         except KeyError:
104                                 return None
105                 else:
106                         raise AttributeError('The \'%s\' attribute can only be accessed from %s instances.' % (self.field.name, owner.__name__))
107         
108         def __set__(self, instance, value):
109                 if isinstance(value, (models.Model, type(None))):
110                         if self.field.key in instance._removed_relationship_registry:
111                                 instance._removed_relationship_registry.remove(self.field.key)
112                         instance._added_relationship_registry[self.field.key] = value
113                 else:
114                         raise AttributeError('The \'%s\' attribute can only be set using existing Model objects.' % self.field.name)
115         
116         def __delete__(self, instance):
117                 if self.field.key in instance._added_relationship_registry:
118                         del instance._added_relationship_registry[self.field.key]
119                 instance._removed_relationship_registry.append(self.field.key)
120
121
122 class RelationshipField(EntityProxyField):
123         descriptor_class = RelationshipFieldDescriptor
124         
125         def __init__(self, model, limit_choices_to=None, key=None, **kwargs):
126                 super(RelationshipField, self).__init__(**kwargs)
127                 self.key = key
128                 self.model = model
129                 if limit_choices_to is None:
130                         limit_choices_to = {}
131                 self.limit_choices_to = limit_choices_to
132         
133         def contribute_to_class(self, cls, name):
134                 super(RelationshipField, self).contribute_to_class(cls, name)
135                 if self.key is None:
136                         self.key = name
137         
138         def formfield(self, form_class=forms.ModelChoiceField, **kwargs):
139                 defaults = {'required': False, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
140                 defaults.update(kwargs)
141                 return form_class(self.model._default_manager.complex_filter(self.limit_choices_to), **defaults)
142         
143         def value_from_object(self, obj):
144                 relobj = super(RelationshipField, self).value_from_object(obj)
145                 return getattr(relobj, 'pk', None)