Skip to content

Commit

Permalink
Merge fff2a4b into 4fe57fe
Browse files Browse the repository at this point in the history
  • Loading branch information
lorinkoz committed May 6, 2020
2 parents 4fe57fe + fff2a4b commit 6414911
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 75 deletions.
10 changes: 5 additions & 5 deletions django_pgschemas/apps.py
Expand Up @@ -17,10 +17,6 @@ def _check_tenant_dict(self):
def _check_public_schema(self):
if not isinstance(settings.TENANTS.get("public"), dict):
raise ImproperlyConfigured("TENANTS must contain a 'public' dict.")
if "TENANT_MODEL" not in settings.TENANTS["public"]:
raise ImproperlyConfigured("TENANTS['public'] must contain a 'TENANT_MODEL' key.")
if "DOMAIN_MODEL" not in settings.TENANTS["public"]:
raise ImproperlyConfigured("TENANTS['public'] must contain a 'DOMAIN_MODEL' key.")
if "URLCONF" in settings.TENANTS["public"]:
raise ImproperlyConfigured("TENANTS['public'] cannot contain a 'URLCONF' key.")
if "WS_URLCONF" in settings.TENANTS["public"]:
Expand All @@ -33,6 +29,10 @@ def _check_public_schema(self):
def _check_default_schemas(self):
if not isinstance(settings.TENANTS.get("default"), dict):
raise ImproperlyConfigured("TENANTS must contain a 'default' dict.")
if "TENANT_MODEL" not in settings.TENANTS["default"]:
raise ImproperlyConfigured("TENANTS['default'] must contain a 'TENANT_MODEL' key.")
if "DOMAIN_MODEL" not in settings.TENANTS["default"]:
raise ImproperlyConfigured("TENANTS['default'] must contain a 'DOMAIN_MODEL' key.")
if "URLCONF" not in settings.TENANTS["default"]:
raise ImproperlyConfigured("TENANTS['default'] must contain a 'URLCONF' key.")
if "DOMAINS" in settings.TENANTS["default"]:
Expand All @@ -43,7 +43,7 @@ def _check_default_schemas(self):
"CLONE_REFERENCE" in settings.TENANTS["default"]
and settings.TENANTS["default"]["CLONE_REFERENCE"] in settings.TENANTS
):
raise ImproperlyConfigured("TENANTS['default']['CLONE_REFERENCE'] must be a unique schema name")
raise ImproperlyConfigured("TENANTS['default']['CLONE_REFERENCE'] must be a unique schema name.")

def _check_overall_schemas(self):
for schema in settings.TENANTS:
Expand Down
2 changes: 1 addition & 1 deletion django_pgschemas/models.py
Expand Up @@ -103,7 +103,7 @@ class DomainMixin(models.Model):
"""

tenant = models.ForeignKey(
settings.TENANTS["public"]["TENANT_MODEL"], db_index=True, related_name="domains", on_delete=models.CASCADE
settings.TENANTS["default"]["TENANT_MODEL"], db_index=True, related_name="domains", on_delete=models.CASCADE
)

domain = models.CharField(max_length=253, db_index=True)
Expand Down
4 changes: 2 additions & 2 deletions django_pgschemas/utils.py
Expand Up @@ -9,12 +9,12 @@

def get_tenant_model(require_ready=True):
"Returns the tenant model."
return apps.get_model(settings.TENANTS["public"]["TENANT_MODEL"], require_ready=require_ready)
return apps.get_model(settings.TENANTS["default"]["TENANT_MODEL"], require_ready=require_ready)


def get_domain_model(require_ready=True):
"Returns the domain model."
return apps.get_model(settings.TENANTS["public"]["DOMAIN_MODEL"], require_ready=require_ready)
return apps.get_model(settings.TENANTS["default"]["DOMAIN_MODEL"], require_ready=require_ready)


def get_tenant_database_alias():
Expand Down
8 changes: 4 additions & 4 deletions docs/advanced.rst
Expand Up @@ -4,7 +4,7 @@ Advanced configuration
Fast dynamic tenant creation
----------------------------

Every time a instance of ``settings.TENANTS["public"]["TENANT_MODEL"]`` is
Every time a instance of ``settings.TENANTS["default"]["TENANT_MODEL"]`` is
created, by default, the corresponding schema is created and synchronized
automatically. Depending on the number of migrations you already have in place,
or the amount of time these could take, or whether you need to pre-populate the
Expand Down Expand Up @@ -95,8 +95,6 @@ Something like this would be the proper configuration for the present case:
"shared_app",
# ...
],
"TENANT_MODEL": "shared_app.Client",
"DOMAIN_MODEL": "shared_app.Domain",
},
"main": {
"APPS": [
Expand All @@ -110,6 +108,8 @@ Something like this would be the proper configuration for the present case:
"URLCONF": "main_app.urls",
},
"default": {
"TENANT_MODEL": "shared_app.Client",
"DOMAIN_MODEL": "shared_app.Domain",
"APPS": [
"django.contrib.auth",
"django.contrib.sessions",
Expand Down Expand Up @@ -252,7 +252,7 @@ The base commands are:
``django_pgschemas.schema.SchemaDescriptor``. Make sure you do the
appropriate type checking before accessing the tenant members, as not every
tenant will be an instance of
``settings.TENANTS["public"]["TENANT_MODEL"]``.
``settings.TENANTS["default"]["TENANT_MODEL"]``.

Caching
-------
Expand Down
8 changes: 4 additions & 4 deletions docs/basic.rst
Expand Up @@ -65,11 +65,11 @@ Add the minimal tenant configuration.
"shared_app",
# ...
],
"TENANT_MODEL": "shared_app.Client",
"DOMAIN_MODEL": "shared_app.Domain",
},
# ...
"default": {
"TENANT_MODEL": "shared_app.Client",
"DOMAIN_MODEL": "shared_app.Domain",
"APPS": [
"django.contrib.auth",
"django.contrib.sessions",
Expand Down Expand Up @@ -138,8 +138,8 @@ More static tenants can be added and routed.
}
Dynamic tenants need to be created through instances of
``TENANTS["public"]["TENANT_MODEL"]`` and routed through instances of
``TENANTS["public"]["DOMAIN_MODEL"]``.
``TENANTS["default"]["TENANT_MODEL"]`` and routed through instances of
``TENANTS["default"]["DOMAIN_MODEL"]``.

.. code-block:: python
Expand Down
4 changes: 2 additions & 2 deletions docs/settings.rst
Expand Up @@ -21,8 +21,6 @@ A sample tenant configuration is:
"shared_app",
# ...
],
"TENANT_MODEL": "shared_app.Client",
"DOMAIN_MODEL": "shared_app.Domain",
},
"www": {
"APPS": [
Expand All @@ -45,6 +43,8 @@ A sample tenant configuration is:
"URLCONF": "blog_app.urls",
},
"default": {
"TENANT_MODEL": "shared_app.Client",
"DOMAIN_MODEL": "shared_app.Domain",
"APPS": [
"django.contrib.auth",
"django.contrib.sessions",
Expand Down
4 changes: 2 additions & 2 deletions dpgs_sandbox/settings.py
Expand Up @@ -30,8 +30,6 @@
TENANTS = {
"public": {
"APPS": ["shared_public", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.staticfiles"],
"TENANT_MODEL": "shared_public.Tenant",
"DOMAIN_MODEL": "shared_public.Domain",
},
"www": {
"APPS": ["shared_common", "app_main", "django.contrib.sessions"],
Expand All @@ -46,6 +44,8 @@
"DOMAINS": ["blog.test.com"],
},
"default": {
"TENANT_MODEL": "shared_public.Tenant",
"DOMAIN_MODEL": "shared_public.Domain",
"APPS": ["shared_common", "app_tenants", "django.contrib.sessions"],
"URLCONF": "app_tenants.urls",
"WS_URLCONF": "app_tenants.ws_urls",
Expand Down
132 changes: 80 additions & 52 deletions dpgs_sandbox/tests/test_apps.py
Expand Up @@ -3,8 +3,7 @@
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase, override_settings

settings_public = {"TENANT_MODEL": "shared_public.Tenant", "DOMAIN_MODEL": "shared_public.Domain"}
settings_default = {"URLCONF": ""}
BASE_DEFAULT = {"TENANT_MODEL": "shared_public.Tenant", "DOMAIN_MODEL": "shared_public.Domain", "URLCONF": ""}


class AppConfigTestCase(TestCase):
Expand All @@ -18,138 +17,167 @@ def setUp(self):
@override_settings()
def test_missing_tenants(self):
del settings.TENANTS
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_tenant_dict()
self.assertEqual(str(ctx.exception), "TENANTS dict setting not set.")

@override_settings(TENANTS=list)
def test_wrong_type_tenants(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_tenant_dict()
self.assertEqual(str(ctx.exception), "TENANTS dict setting not set.")

@override_settings(TENANTS={})
def test_no_public(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_public_schema()
self.assertEqual(str(ctx.exception), "TENANTS must contain a 'public' dict.")

@override_settings(TENANTS={"public": None})
def test_wrong_type_public(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_public_schema()
self.assertEqual(str(ctx.exception), "TENANTS must contain a 'public' dict.")

@override_settings(TENANTS={"public": 4})
def test_other_type_public(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_public_schema()
self.assertEqual(str(ctx.exception), "TENANTS must contain a 'public' dict.")

@override_settings(TENANTS={"public": {"DOMAIN_MODEL": ""}})
def test_no_tenant_model_public(self):
with self.assertRaises(ImproperlyConfigured):
self.app_config._check_public_schema()

@override_settings(TENANTS={"public": {"TENANT_MODEL": ""}})
def test_no_domain_model_public(self):
with self.assertRaises(ImproperlyConfigured):
self.app_config._check_public_schema()

@override_settings(TENANTS={"public": {**settings_public, "URLCONF": ""}})
@override_settings(TENANTS={"public": {"URLCONF": ""}})
def test_urlconf_on_public(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_public_schema()
self.assertEqual(str(ctx.exception), "TENANTS['public'] cannot contain a 'URLCONF' key.")

@override_settings(TENANTS={"public": {**settings_public, "WS_URLCONF": ""}})
@override_settings(TENANTS={"public": {"WS_URLCONF": ""}})
def test_wsurlconf_on_public(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_public_schema()
self.assertEqual(str(ctx.exception), "TENANTS['public'] cannot contain a 'WS_URLCONF' key.")

@override_settings(TENANTS={"public": {**settings_public, "DOMAINS": ""}})
@override_settings(TENANTS={"public": {"DOMAINS": ""}})
def test_domains_on_public(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_public_schema()
self.assertEqual(str(ctx.exception), "TENANTS['public'] cannot contain a 'DOMAINS' key.")

@override_settings(TENANTS={"public": {**settings_public, "FALLBACK_DOMAINS": ""}})
@override_settings(TENANTS={"public": {"FALLBACK_DOMAINS": ""}})
def test_fallback_domains_on_public(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_public_schema()
self.assertEqual(str(ctx.exception), "TENANTS['public'] cannot contain a 'FALLBACK_DOMAINS' key.")

@override_settings(TENANTS=settings_public)
@override_settings(TENANTS={})
def test_no_default(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_default_schemas()
self.assertEqual(str(ctx.exception), "TENANTS must contain a 'default' dict.")

@override_settings(TENANTS={"default": None})
def test_wrong_type_default(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_default_schemas()
self.assertEqual(str(ctx.exception), "TENANTS must contain a 'default' dict.")

@override_settings(TENANTS={"default": "wawa"})
def test_other_type_default(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_default_schemas()
self.assertEqual(str(ctx.exception), "TENANTS must contain a 'default' dict.")

@override_settings(TENANTS={"default": {"DOMAIN_MODEL": ""}})
def test_no_tenant_model_default(self):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_default_schemas()
self.assertEqual(str(ctx.exception), "TENANTS['default'] must contain a 'TENANT_MODEL' key.")

@override_settings(TENANTS={"default": {"TENANT_MODEL": ""}})
def test_no_domain_model_default(self):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_default_schemas()
self.assertEqual(str(ctx.exception), "TENANTS['default'] must contain a 'DOMAIN_MODEL' key.")

@override_settings(TENANTS={"default": {}})
@override_settings(TENANTS={"default": {"TENANT_MODEL": None, "DOMAIN_MODEL": None}})
def test_no_urlconf_default(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_default_schemas()
self.assertEqual(str(ctx.exception), "TENANTS['default'] must contain a 'URLCONF' key.")

@override_settings(TENANTS={"default": {**settings_default, "DOMAINS": ""}})
@override_settings(TENANTS={"default": {**BASE_DEFAULT, "DOMAINS": ""}})
def test_domains_on_default(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_default_schemas()
self.assertEqual(str(ctx.exception), "TENANTS['default'] cannot contain a 'DOMAINS' key.")

@override_settings(TENANTS={"default": {**settings_default, "FALLBACK_DOMAINS": ""}})
@override_settings(TENANTS={"default": {**BASE_DEFAULT, "FALLBACK_DOMAINS": ""}})
def test_fallback_domains_on_default(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_default_schemas()
self.assertEqual(str(ctx.exception), "TENANTS['default'] cannot contain a 'FALLBACK_DOMAINS' key.")

def test_repeated_clone_reference(self):
with override_settings(TENANTS={"public": {}, "default": {**settings_default, "CLONE_REFERENCE": "public"}}):
with self.assertRaises(ImproperlyConfigured):
with override_settings(TENANTS={"public": {}, "default": {**BASE_DEFAULT, "CLONE_REFERENCE": "public"}}):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_default_schemas()
with override_settings(TENANTS={"default": {**settings_default, "CLONE_REFERENCE": "default"}}):
with self.assertRaises(ImproperlyConfigured):
self.assertEqual(str(ctx.exception), "TENANTS['default']['CLONE_REFERENCE'] must be a unique schema name.")
with override_settings(TENANTS={"default": {**BASE_DEFAULT, "CLONE_REFERENCE": "default"}}):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_default_schemas()
self.assertEqual(str(ctx.exception), "TENANTS['default']['CLONE_REFERENCE'] must be a unique schema name.")

def test_valid_schema_name(self):
with override_settings(TENANTS={"pg_whatever": {}}):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_overall_schemas()
self.assertEqual(str(ctx.exception), "'pg_whatever' is not a valid schema name.")
with override_settings(TENANTS={"&$&*": {}}):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_overall_schemas()
self.assertEqual(str(ctx.exception), "'&$&*' is not a valid schema name.")

@override_settings(TENANTS={"www": {}})
def test_domains_on_others(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_overall_schemas()
self.assertEqual(str(ctx.exception), "TENANTS['www'] must contain a 'DOMAINS' list.")

@override_settings(DATABASE_ROUTERS=())
def test_database_routers(self):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_complementary_settings()
self.assertEqual(
str(ctx.exception), "DATABASE_ROUTERS setting must contain 'django_pgschemas.routers.SyncRouter'."
)

def test_extra_search_paths(self):
with override_settings(
TENANTS={"public": settings_public, "default": {}, "www": {}}, PGSCHEMAS_EXTRA_SEARCH_PATHS=["public"]
TENANTS={"public": {}, "default": BASE_DEFAULT, "www": {}}, PGSCHEMAS_EXTRA_SEARCH_PATHS=["public"]
):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_extra_search_paths()
self.assertEqual(str(ctx.exception), "Do not include 'public' on PGSCHEMAS_EXTRA_SEARCH_PATHS.")
with override_settings(
TENANTS={"public": settings_public, "default": {}, "www": {}}, PGSCHEMAS_EXTRA_SEARCH_PATHS=["default"]
TENANTS={"public": {}, "default": BASE_DEFAULT, "www": {}}, PGSCHEMAS_EXTRA_SEARCH_PATHS=["default"]
):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_extra_search_paths()
self.assertEqual(str(ctx.exception), "Do not include 'default' on PGSCHEMAS_EXTRA_SEARCH_PATHS.")
with override_settings(
TENANTS={"public": settings_public, "default": {}, "www": {}}, PGSCHEMAS_EXTRA_SEARCH_PATHS=["www"]
TENANTS={"public": {}, "default": BASE_DEFAULT, "www": {}}, PGSCHEMAS_EXTRA_SEARCH_PATHS=["www"]
):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_extra_search_paths()
self.assertEqual(str(ctx.exception), "Do not include 'www' on PGSCHEMAS_EXTRA_SEARCH_PATHS.")
with override_settings(
TENANTS={"public": settings_public, "default": {"CLONE_REFERENCE": "sample"}, "www": {}},
TENANTS={"public": {}, "default": {**BASE_DEFAULT, "CLONE_REFERENCE": "sample"}, "www": {}},
PGSCHEMAS_EXTRA_SEARCH_PATHS=["sample"],
):
with self.assertRaises(ImproperlyConfigured):
with self.assertRaises(ImproperlyConfigured) as ctx:
self.app_config._check_extra_search_paths()
self.assertEqual(str(ctx.exception), "Do not include 'sample' on PGSCHEMAS_EXTRA_SEARCH_PATHS.")

@override_settings(TENANTS={"public": settings_public, "default": settings_default})
@override_settings(TENANTS={"public": {}, "default": BASE_DEFAULT})
def test_all_good_here(self):
self.app_config.ready()

0 comments on commit 6414911

Please sign in to comment.