mirror of
https://github.com/jazzband/django-eav2.git
synced 2026-05-01 20:24:51 +00:00
Added new fields, validation, etc...
This commit is contained in:
parent
d7ba2ee4f0
commit
a77b1e3e6e
3 changed files with 53 additions and 28 deletions
18
fields.py
18
fields.py
|
|
@ -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'
|
||||
|
|
|
|||
46
models.py
46
models.py
|
|
@ -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():
|
||||
|
|
|
|||
|
|
@ -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'))
|
||||
|
|
|
|||
Loading…
Reference in a new issue