Added new fields, validation, etc...

This commit is contained in:
David Gelvin 2010-09-07 10:11:09 +00:00
parent d7ba2ee4f0
commit a77b1e3e6e
3 changed files with 53 additions and 28 deletions

View file

@ -1,7 +1,18 @@
import uuid
import re
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext as _
from django.core.exceptions import ValidationError
class EavSlugField(models.SlugField):
def validate(self, value, instance):
super(EavSlugField, self).validate(value, instance)
slug_regex = r'[a-z]+[a-z0-9_]*'
if not re.match(slug_regex, value):
raise ValidationError(_(u"Must be all lower case, "\
u"not start with a number, and contain "\
u"only letters, numbers, or underscores."))
class UuidField(models.CharField):
@ -13,7 +24,8 @@ class UuidField(models.CharField):
'''
__metaclass__ = models.SubfieldBase
def __init__(self, version=4, node=None, clock_seq=None, namespace=None, auto=False, name=None, *args, **kwargs):
def __init__(self, version=4, node=None, clock_seq=None,
namespace=None, auto=False, name=None, *args, **kwargs):
self.auto = auto
self.version = version
# Set this as a fixed value, we store UUIDs in text.
@ -36,7 +48,7 @@ class UuidField(models.CharField):
args = (self.namespace, self.name)
else:
args = ()
return getattr(uuid, 'uuid%s' % (self.version,))(*args)
return getattr(uuid, 'uuid%s' % self.version)(*args)
def db_type(self):
return 'char'

View file

@ -1,9 +1,11 @@
import re
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from .fields import UuidField
from .fields import UuidField, EavSlugField
class EavAttributeLabel(models.Model):
@ -16,11 +18,11 @@ class EavAttribute(models.Model):
The A model in E-A-V. This holds the 'concepts' along with the data type
something like:
>>> EavAttribute.objects.create(name='height', datatype='float')
<EavAttribute: height (Float)>
>>> EavAttribute.objects.create(name='Height', datatype='float', slug='height')
<EavAttribute: Height (Float)>
>>> EavAttribute.objects.create(name='color', datatype='text')
<EavAttribute: color (Text)>
>>> EavAttribute.objects.create(name='Color', datatype='text', slug='color')
<EavAttribute: Color (Text)>
'''
class Meta:
ordering = ['name']
@ -41,22 +43,34 @@ class EavAttribute(models.Model):
#(TYPE_MANY, _('multiple choices')),
)
#TODO Force name to lowercase? Don't allow spaces in name
slug = EavSlugField(_(u"slug"), max_length=50, db_index=True,
help_text=_(u"Short unique attribute label"),
unique=True)
name = models.CharField(_(u"name"), max_length=100,
help_text=_(u"User-friendly attribute name"))
help_text = models.CharField(_(u"help text"), max_length=250,
help_text = models.CharField(_(u"help text"), max_length=256,
blank=True, null=True,
help_text=_(u"Short description"))
datatype = models.CharField(_(u"data type"), max_length=6,
choices=DATATYPE_CHOICES)
uuid = UuidField(_(u"UUID"), auto=True)
uuid = UuidField(verbose_name=_(u"UUID"), auto=True, db_index=True)
labels = models.ManyToManyField(EavAttributeLabel,
verbose_name=_(u"labels"))
def save(self, *args, **kwargs):
self.full_clean()
super(EavAttribute, self).save(*args, **kwargs)
def add_label(self, label):
pass
def get_value_for_entity(self, entity):
'''
Passed any object that may be used as an 'entity' object (is linked
@ -135,8 +149,8 @@ class EavEntity(object):
def __getattr__(self, name):
if not name.startswith('_'):
if name in self.get_all_attribute_names():
attribute = self.get_attribute_by_name(name)
if slug in self.get_all_attribute_slugs():
attribute = self.get_attribute_by_slug(name)
value = attribute.get_value_for_entity(self.model)
return value.value if value else None
raise AttributeError(_(u"%s EAV does not have attribute " \
@ -145,8 +159,8 @@ class EavEntity(object):
def save(self):
for attribute in self.get_all_attributes():
if hasattr(self, attribute.name):
attribute_value = getattr(self, attribute.name)
if hasattr(self, attribute.slug):
attribute_value = getattr(self, attribute.slug)
attribute.save_value(self.model, attribute_value)
def get_all_attributes(self):
@ -157,22 +171,22 @@ class EavEntity(object):
pass
self._attributes_cache = self.get_eav_attributes().select_related()
self._attributes_cache_dict = dict((s.name, s) for s in self._attributes_cache)
self._attributes_cache_dict = dict((s.slug, s) for s in self._attributes_cache)
return self._attributes_cache
def get_values(self):
return EavValue.objects.filter(content_type=self.ct,
object_id=self.model.pk).select_related()
def get_all_attribute_names(self):
def get_all_attribute_slugs(self):
if not hasattr(self, '_attributes_cache_dict'):
self.get_all_attributes()
return self._attributes_cache_dict.keys()
def get_attribute_by_name(self, name):
def get_attribute_by_slug(self, slug):
if not hasattr(self, '_attributes_cache_dict'):
self.get_all_attributes()
return self._attributes_cache_dict[name]
return self._attributes_cache_dict[slug]
def get_attribute_by_id(self, attribute_id):
for attr in self.get_all_attributes():

View file

@ -16,8 +16,8 @@ class EavBasicTests(TestCase):
EavRegistry.register(Patient)
self.attribute = EavAttribute.objects.create(datatype=EavAttribute.TYPE_TEXT,
name='City',
help_text='The City')
name='City', help_text='The City', slug='city')
self.entity = Patient.objects.create(name="Doe")
self.value = EavValue.objects.create(object=self.entity,
@ -31,7 +31,7 @@ class EavBasicTests(TestCase):
def test_can_create_attribute(self):
EavAttribute.objects.create(datatype=EavAttribute.TYPE_TEXT,
name='My text test',
name='My text test', slug='test',
help_text='My help text')
def test_attribute_unicode(self):
@ -58,7 +58,7 @@ class EavBasicTests(TestCase):
def test_value_types(self):
_text = EavAttribute.objects.create(datatype=EavAttribute.TYPE_TEXT,
name='Text',
name='Text', slug='text',
help_text='The text')
val = EavValue.objects.create(object=self.entity,
attribute = _text)
@ -68,7 +68,7 @@ class EavBasicTests(TestCase):
self.assertEqual(val.value, value)
_float = EavAttribute.objects.create(datatype=EavAttribute.TYPE_FLOAT,
name='Float',
name='Float', slug='float',
help_text='The float')
val = EavValue.objects.create(object=self.entity,
attribute = _float)
@ -79,7 +79,7 @@ class EavBasicTests(TestCase):
_int = EavAttribute.objects.create(datatype=EavAttribute.TYPE_INT,
name='Int',
name='Int', slug='int',
help_text='The int')
val = EavValue.objects.create(object=self.entity,
attribute = _int)
@ -89,7 +89,7 @@ class EavBasicTests(TestCase):
self.assertEqual(val.value, value)
_date = EavAttribute.objects.create(datatype=EavAttribute.TYPE_DATE,
name='Date',
name='Date', slug='date',
help_text='The date')
val = EavValue.objects.create(object=self.entity,
attribute = _date)
@ -99,7 +99,7 @@ class EavBasicTests(TestCase):
self.assertEqual(val.value, value)
_bool = EavAttribute.objects.create(datatype=EavAttribute.TYPE_BOOLEAN,
name='Bool',
name='Bool', slug='bool',
help_text='The bool')
val = EavValue.objects.create(object=self.entity,
attribute = _bool)
@ -120,7 +120,6 @@ class EavBasicTests(TestCase):
def test_eavregistry_ataches_and_detaches_eav_attribute(self):
from ..utils import EavRegistry
EavRegistry.unregister(Patient)
p = Patient()
self.assertFalse(hasattr(p, 'eav'))