From a2f21c4efa6de69fb65fef10bcb11bb90d543824 Mon Sep 17 00:00:00 2001 From: Musa Date: Fri, 4 May 2018 13:48:35 +0100 Subject: [PATCH] added python 3 and uuid entity id support --- .gitignore | 3 ++ README.rst | 1 + docs/index.rst | 5 ++- eav/admin.py | 2 + eav/migrations/0003_auto_20161104_0922.py | 51 +++++++++++++++++++++++ eav/models.py | 26 +++++++----- eav/registry.py | 2 +- eav/utils/__init__.py | 0 eav/utils/utilities.py | 16 +++++++ requirements.txt | 2 + 10 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 eav/migrations/0003_auto_20161104_0922.py create mode 100644 eav/utils/__init__.py create mode 100644 eav/utils/utilities.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore index 99bcd19..5450e24 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ _build build django_eav.egg-info/* +*.DS_Store +env/ +.idea/ diff --git a/README.rst b/README.rst index ec5999f..7234084 100644 --- a/README.rst +++ b/README.rst @@ -5,6 +5,7 @@ django-eav Introduction ------------ + django-eav provides an Entity-Attribute-Value storage model for django apps. For a decent explanation of what an Entity-Attribute-Value storage model is, diff --git a/docs/index.rst b/docs/index.rst index 47474f9..2567831 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -139,6 +139,9 @@ For example:: eav.register(MyModel, MyEavConfigClass) +To override ``entity_id`` to use ``entity_uuid`` for entity relationship with +model add ``EAV_ENTITY_ID_TYPE='uuid'`` to use ``entity_uuid`` (defaults to +int for ``entity_id``) Using Attributes ================ @@ -151,7 +154,7 @@ First, let's create some attributes:: >>> Attribute.objects.create(name='Weight', datatype=Attribute.TYPE_FLOAT) >>> Attribute.objects.create(name='Height', datatype=Attribute.TYPE_INT) - >>> Attribute.objects.create(name='Is pregant?', datatype=Attribute.TYPE_BOOLEAN) + >>> Attribute.objects.create(name='Is pregnant?', datatype=Attribute.TYPE_BOOLEAN) Now let's create a patient, and set some of these attributes:: diff --git a/eav/admin.py b/eav/admin.py index 70c3ad7..b8469d0 100644 --- a/eav/admin.py +++ b/eav/admin.py @@ -27,6 +27,7 @@ from .models import Attribute, Value, EnumValue, EnumGroup + class BaseEntityAdmin(ModelAdmin): def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): @@ -93,6 +94,7 @@ def get_fieldsets(self, request, obj=None): return [(None, {'fields': list(form.fields.keys())})] + class AttributeAdmin(ModelAdmin): list_display = ('name', 'content_type', 'slug', 'datatype', 'description', 'site') list_filter = ['site'] diff --git a/eav/migrations/0003_auto_20161104_0922.py b/eav/migrations/0003_auto_20161104_0922.py new file mode 100644 index 0000000..9da9f11 --- /dev/null +++ b/eav/migrations/0003_auto_20161104_0922.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2016-11-04 09:22 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import eav.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('eav', '0002_auto_20161014_0157'), + ] + + operations = [ + migrations.CreateModel( + name='Encounter', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('num', models.PositiveSmallIntegerField()), + ], + ), + migrations.CreateModel( + name='Patient', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=12)), + ], + ), + migrations.AlterField( + model_name='attribute', + name='datatype', + field=eav.fields.EavDatatypeField(choices=[('text', 'Text'), ('float', 'Float'), ('int', 'Integer'), ('date', 'Date'), ('bool', 'True / False'), ('object', 'Django Object'), ('enum', 'Multiple Choice')], max_length=6, verbose_name='data type'), + ), + migrations.AddField( + model_name='encounter', + name='patient', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eav.Patient'), + ), + migrations.AddField( + model_name='value', + name='entity_uuid', + field=models.UUIDField(blank=True, null=True), + ), + migrations.AlterField( + model_name='value', + name='entity_id', + field=models.IntegerField(blank=True, null=True), + ), + ] diff --git a/eav/models.py b/eav/models.py index b5ea562..612eff7 100644 --- a/eav/models.py +++ b/eav/models.py @@ -49,6 +49,7 @@ from .validators import * from .fields import EavSlugField, EavDatatypeField +from .utils.utilities import Utils class EnumValue(models.Model): @@ -86,7 +87,7 @@ class EnumValue(models.Model): @python_2_unicode_compatible def __str__(self): return self.value - + class EnumGroup(models.Model): ''' @@ -304,16 +305,15 @@ def save_value(self, entity, value): Attribute and *entity*, it will delete that :class:`Value` object. ''' ct = ContentType.objects.get_for_model(entity) + entity_dict = dict(entity_ct=ct, + attribute=self) + entity_dict[Value.entity_id_type] = entity.pk try: - value_obj = self.value_set.get(entity_ct=ct, - entity_id=entity.pk, - attribute=self) + value_obj = self.value_set.get(**entity_dict) except Value.DoesNotExist: if value == None or value == '': return - value_obj = Value.objects.create(entity_ct=ct, - entity_id=entity.pk, - attribute=self) + value_obj = Value.objects.create(**entity_dict) if value == None or value == '': value_obj.delete() return @@ -347,10 +347,13 @@ class Value(models.Model): ''' + entity_id_type = Utils().get_eav_entity_id_type() + entity_ct = models.ForeignKey(ContentType, related_name='value_entities') - entity_id = models.IntegerField() + entity_id = models.IntegerField(blank=True, null=True) + entity_uuid = models.UUIDField(blank=True, null=True) entity = generic.GenericForeignKey(ct_field='entity_ct', - fk_field='entity_id') + fk_field=entity_id_type) value_text = models.TextField(blank=True, null=True) value_float = models.FloatField(blank=True, null=True) @@ -521,8 +524,9 @@ def get_values(self): ''' Get all set :class:`Value` objects for self.model ''' - return Value.objects.filter(entity_ct=self.ct, - entity_id=self.model.pk).select_related() + entiity_filter = dict(entity_ct=self.ct) + entiity_filter[Value.entity_id_type] = self.model.pk + return Value.objects.filter(**entiity_filter).select_related() def get_all_attribute_slugs(self): ''' diff --git a/eav/registry.py b/eav/registry.py index 340e310..6a6a598 100644 --- a/eav/registry.py +++ b/eav/registry.py @@ -165,7 +165,7 @@ def _attach_generic_relation(self): gr_name = self.config_cls.generic_relation_attr.lower() generic_relation = \ generic.GenericRelation(Value, - object_id_field='entity_id', + object_id_field=Value.entity_id_type, content_type_field='entity_ct', related_query_name=rel_name) generic_relation.contribute_to_class(self.model_cls, gr_name) diff --git a/eav/utils/__init__.py b/eav/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/eav/utils/utilities.py b/eav/utils/utilities.py new file mode 100644 index 0000000..1878524 --- /dev/null +++ b/eav/utils/utilities.py @@ -0,0 +1,16 @@ +from django.conf import settings + + +class Utils(object): + ENTITY_ID_TYPES = { + 'uuid': 'entity_uuid', + 'int': 'entity_id' + } + + def get_eav_entity_id_type(self): + key = getattr(settings, 'EAV_ENTITY_ID_TYPE', 'int') + try: + return self.ENTITY_ID_TYPES[key] + except KeyError: + print('%s not supported, kindly try uuid or int, defaulting to int' % key) + return self.ENTITY_ID_TYPES['int'] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3d21135 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Django==1.10.3 +eav-django==1.4.7