From 142edc509b99b0d70e2c0c682445fe07baa6650d Mon Sep 17 00:00:00 2001 From: Oliver Roick Date: Mon, 30 Nov 2015 16:09:25 +0000 Subject: [PATCH] Add RandomIDModel Add RandomIDModel is an abstract base model that creates a random alpha-numeric ID for the model instance. All Cadasta models must inherit from this class. --- cadasta/config/settings/default.py | 2 -- cadasta/core/models.py | 26 ++++++++++++++++++++++++++ cadasta/core/tests/__init__.py | 0 cadasta/core/tests/test_models.py | 11 +++++++++++ cadasta/core/tests/testcases.py | 30 ++++++++++++++++++++++++++++++ cadasta/core/util.py | 19 +++++++++++++++++++ 6 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 cadasta/core/models.py create mode 100644 cadasta/core/tests/__init__.py create mode 100644 cadasta/core/tests/test_models.py create mode 100644 cadasta/core/tests/testcases.py create mode 100644 cadasta/core/util.py diff --git a/cadasta/config/settings/default.py b/cadasta/config/settings/default.py index cb74647b4..9a2d323d0 100644 --- a/cadasta/config/settings/default.py +++ b/cadasta/config/settings/default.py @@ -33,8 +33,6 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - - 'organizations' ) MIDDLEWARE_CLASSES = ( diff --git a/cadasta/core/models.py b/cadasta/core/models.py new file mode 100644 index 000000000..2ca8bb9c6 --- /dev/null +++ b/cadasta/core/models.py @@ -0,0 +1,26 @@ +from django.db import models + +from .util import random_id, ID_FIELD_LENGTH + + +class RandomIDModel(models.Model): + id = models.CharField(primary_key=True, max_length=ID_FIELD_LENGTH) + + class Meta: + abstract = True + + def save(self, *args, **kwargs): + if not self.id: + kwargs['force_insert'] = True + + while True: + self.id = random_id() + + if not type(self).objects.filter(pk=self.id).exists(): + super(RandomIDModel, self).save(*args, **kwargs) + break + else: + continue + + else: + super(RandomIDModel, self).save(*args, **kwargs) diff --git a/cadasta/core/tests/__init__.py b/cadasta/core/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/cadasta/core/tests/test_models.py b/cadasta/core/tests/test_models.py new file mode 100644 index 000000000..3a527ed4d --- /dev/null +++ b/cadasta/core/tests/test_models.py @@ -0,0 +1,11 @@ +from .testcases import AbstractModelTestCase +from ..models import RandomIDModel + + +class RandomIDModelTest(AbstractModelTestCase): + abstract_model = RandomIDModel + + def test_save(self): + instance = self.model() + instance.save() + self.assertIsNotNone(instance.id) diff --git a/cadasta/core/tests/testcases.py b/cadasta/core/tests/testcases.py new file mode 100644 index 000000000..ef16eec23 --- /dev/null +++ b/cadasta/core/tests/testcases.py @@ -0,0 +1,30 @@ +from django.test import TestCase +from django.db import connection +from django.core.management.color import no_style +from django.db.models.base import ModelBase + + +class AbstractModelTestCase(TestCase): + def setUp(self): + # Create a dummy model which extends the abstract model + self.model = ModelBase( + '__TestModel__' + self.abstract_model.__name__, + (self.abstract_model,), + {'__module__': self.abstract_model.__module__} + ) + + # Create the schema for our test model + self._style = no_style() + sql, _ = connection.creation.sql_create_model(self.model, self._style) + + self._cursor = connection.cursor() + for statement in sql: + self._cursor.execute(statement) + + def tearDown(self): + # Delete the schema for the test model + sql = connection.creation.sql_destroy_model( + self.model, (), self._style + ) + for statement in sql: + self._cursor.execute(statement) diff --git a/cadasta/core/util.py b/cadasta/core/util.py new file mode 100644 index 000000000..86020bf22 --- /dev/null +++ b/cadasta/core/util.py @@ -0,0 +1,19 @@ +import random +import string + + +ID_FIELD_LENGTH = 24 + +alphabet = string.ascii_lowercase + string.digits +for loser in 'l1o0': + i = alphabet.index(loser) + alphabet = alphabet[:i] + alphabet[i+1:] + + +def byte_to_base32_chr(byte): + return alphabet[byte & 31] + + +def random_id(): + rand_id = [random.randint(0, 0xFF) for i in range(ID_FIELD_LENGTH)] + return ''.join(map(byte_to_base32_chr, rand_id))