From 9b56343a81f53bd7b1fec1f07887a01a8ef7a4f3 Mon Sep 17 00:00:00 2001 From: Fabio Caccamo Date: Thu, 28 Mar 2019 12:08:17 +0100 Subject: [PATCH] Added idempotent deploy support. --- .../migrations/0014_name_unique.py | 20 ++++++++ admin_interface/models.py | 14 +++++- tests/test_fixtures.py | 46 +++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 admin_interface/migrations/0014_name_unique.py create mode 100644 tests/test_fixtures.py diff --git a/admin_interface/migrations/0014_name_unique.py b/admin_interface/migrations/0014_name_unique.py new file mode 100644 index 0000000..850d5a5 --- /dev/null +++ b/admin_interface/migrations/0014_name_unique.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('admin_interface', '0013_add_related_modal_close_button'), + ] + + operations = [ + migrations.AlterField( + model_name='theme', + name='name', + field=models.CharField(default='Django', max_length=50, unique=True, verbose_name='name'), + ), + ] diff --git a/admin_interface/models.py b/admin_interface/models.py index 5aa8f96..5c62f52 100644 --- a/admin_interface/models.py +++ b/admin_interface/models.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals from django.db import models -from django.db.models.signals import post_delete, post_save +from django.db.models.signals import post_delete, post_save, pre_save from django.utils.encoding import python_2_unicode_compatible, force_text from django.utils.translation import ugettext_lazy as _ @@ -27,6 +27,16 @@ class Theme(models.Model): Theme.objects.exclude(pk=instance.pk).update(active=False) Theme.get_active_theme() + @staticmethod + def pre_save_handler(instance, **kwargs): + if instance.pk is None: + try: + obj = Theme.objects.get(name=instance.name) + if obj: + instance.pk = obj.pk + except Theme.DoesNotExist: + pass + @staticmethod def get_active_theme(): objs_manager = Theme.objects @@ -51,6 +61,7 @@ class Theme(models.Model): return obj name = models.CharField( + unique=True, max_length=50, default='Django', verbose_name=_('name')) @@ -275,3 +286,4 @@ class Theme(models.Model): post_delete.connect(Theme.post_delete_handler, sender=Theme) post_save.connect(Theme.post_save_handler, sender=Theme) +pre_save.connect(Theme.pre_save_handler, sender=Theme) diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py new file mode 100644 index 0000000..3a08aff --- /dev/null +++ b/tests/test_fixtures.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- + +from django.core.management import call_command +from django.test import TestCase + +from admin_interface.models import Theme + + +class AdminInterfaceFixturesTestCase(TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + def __load_theme(self, theme_name): + call_command('loaddata', 'admin_interface_theme_%s.json' % (theme_name, )) + + def test_import_all(self): + self.__load_theme('django') + self.__load_theme('bootstrap') + self.__load_theme('foundation') + self.__load_theme('uswds') + self.assertEqual(Theme.objects.count(), 4); + + def test_import_idempotency(self): + self.__load_theme('django') + self.__load_theme('django') + self.__load_theme('django') + self.__load_theme('django') + self.__load_theme('django') + self.assertEqual(Theme.objects.count(), 1); + self.__load_theme('bootstrap') + self.__load_theme('bootstrap') + self.__load_theme('bootstrap') + self.assertEqual(Theme.objects.count(), 2); + + def test_import_override(self): + obj1 = Theme.get_active_theme() + obj1.title = 'Custom 1' + obj1.save() + self.__load_theme('django') + obj2 = Theme.get_active_theme() + self.assertEqual(obj1.pk, obj2.pk) + self.assertTrue(obj1.title != obj2.title)