def create_schema(sender, instance, created, **kwargs): """ Actually create the schema in the database. We do this in a signal handler instead of .save() so we can catch those created using raw methods. How do we indicate when we should be using a different template? """ if created: schema_name = instance.schema # How can we work out what values need to go here? # Currently, we just allow a single attribute `_clone`, that, # if set, will indicate that we should clone a schema. template_name = getattr(instance, '_clone', settings.TEMPLATE_SCHEMA) include_records = bool(getattr(instance, '_clone', False)) cursor = connection.cursor() if _schema_exists(schema_name): raise ValueError('Attempt to create an existing schema: {0}'.format(schema_name)) cursor.execute("SELECT clone_schema(%s, %s, %s)", [ template_name, schema_name, include_records ]) cursor.close() if schema_name != settings.TEMPLATE_SCHEMA: signals.schema_created.send(sender=get_schema_model(), schema=schema_name) LOGGER.info('New schema created: %s', schema_name)
def ready(self): if not hasattr(settings, 'BOARDINGHOUSE_TEMPLATE_PREFIX'): settings.BOARDINGHOUSE_TEMPLATE_PREFIX = '__tmpl_' from boardinghouse.schema import get_schema_model from .models import SchemaTemplate from ..template import receivers # NOQA if 'django.contrib.admin' in settings.INSTALLED_APPS: # We can't just add the action to the SchemaAdmin, because that may not be a subclass of ModelAdmin, # in which case the action would be applied to all models. from .admin import create_template_from_schema Schema = get_schema_model() module = import_module( Schema.__module__.rsplit('.', 1)[0] + '.admin') BaseSchemaAdmin = module.admin.site._registry[Schema].__class__ from django.contrib import admin from django import forms admin.site.unregister(Schema) class SchemaAdmin(BaseSchemaAdmin): actions = list(BaseSchemaAdmin.actions or []) + [create_template_from_schema] def get_form(self, request, obj=None, **kwargs): if not obj and 'boardinghouse.contrib.template' in settings.INSTALLED_APPS: class SchemaAdminForm(BaseSchemaAdmin.form or forms.ModelForm): clone_schema = forms.ModelChoiceField( required=False, queryset=SchemaTemplate.objects.all()) kwargs['form'] = SchemaAdminForm return super(SchemaAdmin, self).get_form(request, obj, **kwargs) def get_fields(self, request, obj): fields = super(SchemaAdmin, self).get_fields(request, obj) if 'clone_schema' in fields: fields.remove('clone_schema') return ['clone_schema'] + fields return fields def save_model(self, request, obj, form, change): if not change and form.cleaned_data.get( 'clone_schema') is not None: obj._clone = form.cleaned_data['clone_schema'].schema return super(SchemaAdmin, self).save_model(request, obj, form, change) admin.site.register(Schema, SchemaAdmin)
def ready(self): if self._ready_has_run: return # Make sure that all default settings have been applied (if not overwritten). from boardinghouse import settings as app_settings from django.conf import settings, global_settings for key in dir(app_settings): if key.isupper(): value = getattr(app_settings, key) setattr(global_settings, key, value) if not hasattr(settings, key): setattr(settings, key, value) # Make non-logged-in users unable to view any schemata. from django.contrib.auth import get_user_model, models from boardinghouse.schema import get_schema_model from boardinghouse.models import visible_schemata User = get_user_model() models.AnonymousUser.visible_schemata = get_schema_model().objects.none() if not hasattr(User, 'visible_schemata'): User.visible_schemata = property(visible_schemata) if hasattr(User, 'schemata'): models.AnonymousUser.schemata = get_schema_model().objects.none() # Make sure User <--> Group and User <--> Permission are per-schema. # If this is not desired, then it needs to be overriden. settings.PRIVATE_MODELS.extend([ '{m.app_label}.{m.model_name}'.format(m=User.groups.through._meta).lower(), '{m.app_label}.{m.model_name}'.format(m=User.user_permissions.through._meta).lower() ]) from boardinghouse import receivers # NOQA self._ready_has_run = True
def ready(self): if not hasattr(settings, 'BOARDINGHOUSE_TEMPLATE_PREFIX'): settings.BOARDINGHOUSE_TEMPLATE_PREFIX = '__tmpl_' from boardinghouse.schema import get_schema_model from .models import SchemaTemplate from ..template import receivers # NOQA if 'django.contrib.admin' in settings.INSTALLED_APPS: # We can't just add the action to the SchemaAdmin, because that may not be a subclass of ModelAdmin, # in which case the action would be applied to all models. from .admin import create_template_from_schema Schema = get_schema_model() module = import_module(Schema.__module__.rsplit('.', 1)[0] + '.admin') BaseSchemaAdmin = module.admin.site._registry[Schema].__class__ from django.contrib import admin from django import forms admin.site.unregister(Schema) class SchemaAdmin(BaseSchemaAdmin): actions = list(BaseSchemaAdmin.actions or []) + [create_template_from_schema] def get_form(self, request, obj=None, **kwargs): if not obj and 'boardinghouse.contrib.template' in settings.INSTALLED_APPS: class SchemaAdminForm(BaseSchemaAdmin.form or forms.ModelForm): clone_schema = forms.ModelChoiceField(required=False, queryset=SchemaTemplate.objects.all()) kwargs['form'] = SchemaAdminForm return super(SchemaAdmin, self).get_form(request, obj, **kwargs) def get_fields(self, request, obj): fields = super(SchemaAdmin, self).get_fields(request, obj) if 'clone_schema' in fields: fields.remove('clone_schema') return ['clone_schema'] + fields return fields def save_model(self, request, obj, form, change): if not change and form.cleaned_data.get('clone_schema') is not None: obj._clone = form.cleaned_data['clone_schema'].schema return super(SchemaAdmin, self).save_model(request, obj, form, change) admin.site.register(Schema, SchemaAdmin)
from django.test import TestCase from boardinghouse.schema import get_schema_model from ..models import AwareModel Schema = get_schema_model() class TestMultiSchemaManager(TestCase): def test_multi_schema_fetches_objects_correctly(self): Schema.objects.mass_create('a', 'b') a = Schema.objects.get(name='a') a.activate() AwareModel.objects.create(name='foo') AwareModel.objects.create(name='bar') AwareModel.objects.create(name='baz') b = Schema.objects.get(name='b') b.activate() AwareModel.objects.create(name='foo') AwareModel.objects.create(name='bar') AwareModel.objects.create(name='baz') b.deactivate() objects = list(AwareModel.objects.from_schemata(a)) self.assertEqual(3, len(objects)) objects = list(AwareModel.objects.from_schemata(a, b)) self.assertEqual(6, len(objects))
def test_invalid_schema_model_string(self): settings.BOARDINGHOUSE_SCHEMA_MODEL = 'foo__bar' with self.assertRaises(ImproperlyConfigured): get_schema_model()
def test_schema_model_model_not_found(self): settings.BOARDINGHOUSE_SCHEMA_MODEL = 'boardinghouse.NotSchemaModel' with self.assertRaises(ImproperlyConfigured): get_schema_model()
def test_schema_model_app_not_found(self): settings.BOARDINGHOUSE_SCHEMA_MODEL = 'foo.bar' with self.assertRaises(ImproperlyConfigured): get_schema_model()
def execute_on_all_schemata(sender, db_table, function, **kwargs): if _schema_table_exists(): for each in get_schema_model().objects.all(): each.activate() function(*kwargs.get('args', []), **kwargs.get('kwargs', {}))
def test_no_BOARDINGHOUSE_SCHEMA_MODEL(self): del settings.BOARDINGHOUSE_SCHEMA_MODEL with self.assertRaises(exceptions.ImproperlyConfigured): get_schema_model()
def verbose_name(): if 'makemigrations' in sys.argv: return u'template schema' return u'template {0}'.format(get_schema_model()._meta.verbose_name)
from django.test import TestCase from boardinghouse.schema import get_schema_model from ..models import AwareModel, NaiveModel Schema = get_schema_model() class TestObjectEquality(TestCase): def test_objects_from_different_schema_differ(self): first, second = Schema.objects.mass_create('first', 'second') first.activate() object_1 = AwareModel.objects.create(name="foo") second.activate() object_2 = AwareModel.objects.create(name="foo") self.assertEqual(object_1.pk, object_2.pk) self.assertNotEqual(object_1, object_2, "Objects with the same id from different schemata should not be equal.") def test_objects_from_same_schema_equal(self): first, second = Schema.objects.mass_create('first', 'second') first.activate() AwareModel.objects.create(name="foo") second.activate() object_2 = AwareModel.objects.create(name="foo")