From d2df0951a22529ba232d8b77c050a4245a3fd22a Mon Sep 17 00:00:00 2001 From: Adnan Umer Date: Thu, 16 Mar 2017 00:47:17 +0500 Subject: [PATCH 01/11] Django 1.10 Support --- tenant_schemas/template_loaders.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/tenant_schemas/template_loaders.py b/tenant_schemas/template_loaders.py index c8c98ee..7cf1342 100644 --- a/tenant_schemas/template_loaders.py +++ b/tenant_schemas/template_loaders.py @@ -4,16 +4,31 @@ multi-tenant setting """ import hashlib +from django import VERSION as DJANGO_VERSION from django.conf import settings from django.core.exceptions import ImproperlyConfigured -from django.template.base import TemplateDoesNotExist, Template -from django.utils.encoding import force_bytes -from django.utils._os import safe_join from django.db import connection +from django.template.base import Template from django.template.loaders.base import Loader as BaseLoader - +from django.utils._os import safe_join +from django.utils.encoding import force_bytes from tenant_schemas.postgresql_backend.base import FakeTenant +DJANGO_1_10 = DJANGO_VERSION[1] >= 10 + +if DJANGO_1_10: + from django.template import Origin, TemplateDoesNotExist + + + def make_origin(engine, name, loader, template_name, dirs): + return Origin(name=name, template_name=template_name, loader=loader) +else: + from django.template.base import TemplateDoesNotExist + + + def make_origin(engine, name, loader, template_name, dirs): + return engine.make_origin(name, loader, template_name, dirs) + class CachedLoader(BaseLoader): is_usable = True @@ -50,7 +65,7 @@ class CachedLoader(BaseLoader): except TemplateDoesNotExist: pass else: - origin = self.engine.make_origin(display_name, loader, name, dirs) + origin = make_origin(self.engine, display_name, loader, name, dirs) result = template, origin break self.find_template_cache[key] = result @@ -133,4 +148,5 @@ class FilesystemLoader(BaseLoader): else: error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory." raise TemplateDoesNotExist(error_msg) + load_template_source.is_usable = True From 26692945c132b324c6e936849fa9b6e719d66167 Mon Sep 17 00:00:00 2001 From: Adnan Umer Date: Thu, 16 Mar 2017 00:52:07 +0500 Subject: [PATCH 02/11] Updated Django 1.10 Version Check --- tenant_schemas/template_loaders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tenant_schemas/template_loaders.py b/tenant_schemas/template_loaders.py index 7cf1342..24c36da 100644 --- a/tenant_schemas/template_loaders.py +++ b/tenant_schemas/template_loaders.py @@ -14,7 +14,7 @@ from django.utils._os import safe_join from django.utils.encoding import force_bytes from tenant_schemas.postgresql_backend.base import FakeTenant -DJANGO_1_10 = DJANGO_VERSION[1] >= 10 +DJANGO_1_10 = DJANGO_VERSION[0] == 1 and DJANGO_VERSION[1] >= 10 if DJANGO_1_10: from django.template import Origin, TemplateDoesNotExist From 36e1ba3800de51486e03495c6708748b6c0fe13d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Raimbault?= Date: Wed, 12 Apr 2017 07:06:19 +0200 Subject: [PATCH 03/11] Django 1.11 support (#463) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Django 1.11 to Travis - related to #435 - 😉 to tomturner/django-tenants#120 * Replace direct use of import_module by proper load_backend Handle new 'django.db.backends.postgresql' name (Django 1.9) * Fix 'default' already present in _fields in Django 1.11 * Fix not existing access to original_backend.DatabaseError (Django 1.11) Removed exports because django.db.utils.DatabaseError and django.db.utils.IntegrityError must be used instead. This change must be stated in release notes. * The signature of DatabaseWrapper._cursor has changed in Django 1.11 Use the public API * Add missing allowed hosts for tests * Don't override default user or blocks Unix socket DB connection * Updated tox.ini for Django 1.11rc1 * Properly add '.test.com' to ALLOWED_HOSTS in test cases * Internal tests don't use TenantTestCase so set allowed hosts manually * Drop Django 1.9 support Django 1.8 is still within LTS until the end of 2017. --- .travis.yml | 2 +- dts_test_project/dts_test_project/settings.py | 8 +-- tenant_schemas/postgresql_backend/base.py | 51 ++++++++++--------- .../postgresql_backend/introspection.py | 6 ++- tenant_schemas/test/cases.py | 19 ++++++- tenant_schemas/tests/testcases.py | 9 ++++ tox.ini | 7 +-- 7 files changed, 69 insertions(+), 33 deletions(-) diff --git a/.travis.yml b/.travis.yml index d83ff55..3769b5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,8 @@ script: - tox -e py${TRAVIS_PYTHON_VERSION/./}-dj${DJANGO/./} env: - DJANGO=1.8 -- DJANGO=1.9 - DJANGO=1.10 +- DJANGO=1.11 deploy: provider: pypi user: bcarneiro diff --git a/dts_test_project/dts_test_project/settings.py b/dts_test_project/dts_test_project/settings.py index 58716a7..245b017 100644 --- a/dts_test_project/dts_test_project/settings.py +++ b/dts_test_project/dts_test_project/settings.py @@ -82,10 +82,10 @@ DATABASES = { 'default': { 'ENGINE': 'tenant_schemas.postgresql_backend', 'NAME': os.environ.get('PG_NAME', 'dts_test_project'), - 'USER': os.environ.get('PG_USER', 'postgres'), - 'PASSWORD': os.environ.get('PG_PASSWORD', 'root'), - 'HOST': os.environ.get('PG_HOST', 'localhost'), - 'PORT': int(os.environ.get('PG_PORT', '5432')), + 'USER': os.environ.get('PG_USER'), + 'PASSWORD': os.environ.get('PG_PASSWORD'), + 'HOST': os.environ.get('PG_HOST'), + 'PORT': int(os.environ.get('PG_PORT')) if os.environ.get('PG_PORT') else None, } } diff --git a/tenant_schemas/postgresql_backend/base.py b/tenant_schemas/postgresql_backend/base.py index fb3cf1f..08555aa 100644 --- a/tenant_schemas/postgresql_backend/base.py +++ b/tenant_schemas/postgresql_backend/base.py @@ -1,21 +1,17 @@ import re import warnings -from django.conf import settings -try: - # Django versions >= 1.9 - from django.utils.module_loading import import_module -except ImportError: - # Django versions < 1.9 - from django.utils.importlib import import_module -from django.core.exceptions import ImproperlyConfigured, ValidationError -from tenant_schemas.utils import get_public_schema_name, get_limit_set_calls -from tenant_schemas.postgresql_backend.introspection import DatabaseSchemaIntrospection -import django.db.utils import psycopg2 -ORIGINAL_BACKEND = getattr(settings, 'ORIGINAL_BACKEND', 'django.db.backends.postgresql_psycopg2') +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured, ValidationError +import django.db.utils -original_backend = import_module(ORIGINAL_BACKEND + '.base') +from tenant_schemas.utils import get_public_schema_name, get_limit_set_calls +from tenant_schemas.postgresql_backend.introspection import DatabaseSchemaIntrospection + +ORIGINAL_BACKEND = getattr(settings, 'ORIGINAL_BACKEND', 'django.db.backends.postgresql_psycopg2') +# Django 1.9+ takes care to rename the default backend to 'django.db.backends.postgresql' +original_backend = django.db.utils.load_backend(ORIGINAL_BACKEND) EXTRA_SEARCH_PATHS = getattr(settings, 'PG_EXTRA_SEARCH_PATHS', []) @@ -109,12 +105,16 @@ class DatabaseWrapper(original_backend.DatabaseWrapper): category=DeprecationWarning) return self.tenant - def _cursor(self): + def _cursor(self, name=None): """ Here it happens. We hope every Django db operation using PostgreSQL must go through this to get the cursor handle. We change the path. """ - cursor = super(DatabaseWrapper, self)._cursor() + if name: + # Only supported and required by Django 1.11 (server-side cursor) + cursor = super(DatabaseWrapper, self)._cursor(name=name) + else: + cursor = super(DatabaseWrapper, self)._cursor() # optionally limit the number of executions - under load, the execution # of `set search_path` can be quite time consuming @@ -137,16 +137,28 @@ class DatabaseWrapper(original_backend.DatabaseWrapper): search_paths = [self.schema_name] search_paths.extend(EXTRA_SEARCH_PATHS) + + if name: + # Named cursor can only be used once + cursor_for_search_path = self.connection.cursor() + else: + # Reuse + cursor_for_search_path = cursor + # In the event that an error already happened in this transaction and we are going # to rollback we should just ignore database error when setting the search_path # if the next instruction is not a rollback it will just fail also, so # we do not have to worry that it's not the good one try: - cursor.execute('SET search_path = {0}'.format(','.join(search_paths))) + cursor_for_search_path.execute('SET search_path = {0}'.format(','.join(search_paths))) except (django.db.utils.DatabaseError, psycopg2.InternalError): self.search_path_set = False else: self.search_path_set = True + + if name: + cursor_for_search_path.close() + return cursor @@ -157,10 +169,3 @@ class FakeTenant: """ def __init__(self, schema_name): self.schema_name = schema_name - -if ORIGINAL_BACKEND == "django.contrib.gis.db.backends.postgis": - DatabaseError = django.db.utils.DatabaseError - IntegrityError = psycopg2.IntegrityError -else: - DatabaseError = original_backend.DatabaseError - IntegrityError = original_backend.IntegrityError diff --git a/tenant_schemas/postgresql_backend/introspection.py b/tenant_schemas/postgresql_backend/introspection.py index 4128e1e..ca445d4 100644 --- a/tenant_schemas/postgresql_backend/introspection.py +++ b/tenant_schemas/postgresql_backend/introspection.py @@ -7,7 +7,11 @@ from django.db.backends.base.introspection import ( ) from django.utils.encoding import force_text -FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('default',)) +fields = FieldInfo._fields +if 'default' not in fields: + fields += ('default',) + +FieldInfo = namedtuple('FieldInfo', fields) class DatabaseSchemaIntrospection(BaseDatabaseIntrospection): diff --git a/tenant_schemas/test/cases.py b/tenant_schemas/test/cases.py index beb489c..cd05c6b 100644 --- a/tenant_schemas/test/cases.py +++ b/tenant_schemas/test/cases.py @@ -1,15 +1,30 @@ from django.core.management import call_command +from django.conf import settings from django.db import connection from django.test import TestCase from tenant_schemas.utils import get_public_schema_name from tenant_schemas.utils import get_tenant_model +ALLOWED_TEST_DOMAIN = '.test.com' + class TenantTestCase(TestCase): + @classmethod + def add_allowed_test_domain(cls): + # ALLOWED_HOSTS is a special setting of Django setup_test_environment so we can't modify it with helpers + if ALLOWED_TEST_DOMAIN not in settings.ALLOWED_HOSTS: + settings.ALLOWED_HOSTS += [ALLOWED_TEST_DOMAIN] + + @classmethod + def remove_allowed_test_domain(cls): + if ALLOWED_TEST_DOMAIN in settings.ALLOWED_HOSTS: + settings.ALLOWED_HOSTS.remove(ALLOWED_TEST_DOMAIN) + @classmethod def setUpClass(cls): cls.sync_shared() + cls.add_allowed_test_domain() tenant_domain = 'tenant.test.com' cls.tenant = get_tenant_model()(domain_url=tenant_domain, schema_name='test') cls.tenant.save(verbosity=0) # todo: is there any way to get the verbosity from the test command here? @@ -21,6 +36,7 @@ class TenantTestCase(TestCase): connection.set_schema_to_public() cls.tenant.delete() + cls.remove_allowed_test_domain() cursor = connection.cursor() cursor.execute('DROP SCHEMA IF EXISTS test CASCADE') @@ -33,10 +49,10 @@ class TenantTestCase(TestCase): class FastTenantTestCase(TenantTestCase): - @classmethod def setUpClass(cls): cls.sync_shared() + cls.add_allowed_test_domain() tenant_domain = 'tenant.test.com' TenantModel = get_tenant_model() @@ -51,3 +67,4 @@ class FastTenantTestCase(TenantTestCase): @classmethod def tearDownClass(cls): connection.set_schema_to_public() + cls.remove_allowed_test_domain() diff --git a/tenant_schemas/tests/testcases.py b/tenant_schemas/tests/testcases.py index 18531da..558eafa 100644 --- a/tenant_schemas/tests/testcases.py +++ b/tenant_schemas/tests/testcases.py @@ -20,6 +20,8 @@ class BaseTestCase(TestCase): 'django.contrib.contenttypes', 'django.contrib.auth', ) settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS + if '.test.com' not in settings.ALLOWED_HOSTS: + settings.ALLOWED_HOSTS += ['.test.com'] # Django calls syncdb by default for the test database, but we want # a blank public schema for this set of tests. @@ -29,6 +31,13 @@ class BaseTestCase(TestCase): % (get_public_schema_name(), get_public_schema_name())) super(BaseTestCase, cls).setUpClass() + @classmethod + def tearDownClass(cls): + super(BaseTestCase, cls).tearDownClass() + + if '.test.com' in settings.ALLOWED_HOSTS: + settings.ALLOWED_HOSTS.remove('.test.com') + def setUp(self): connection.set_schema_to_public() super(BaseTestCase, self).setUp() diff --git a/tox.ini b/tox.ini index fc4f8c5..6071ab3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,21 +1,22 @@ [tox] -envlist = py{27,35}-dj{18,19,110} +envlist = py{27,35}-dj{18,19,110,111} [testenv] usedevelop = True -deps = +deps = coverage mock tblib dj18: Django~=1.8.0 dj19: Django~=1.9.0 dj110: Django~=1.10.0 + dj111: Django~=1.11rc1 changedir = dts_test_project passenv = PG_NAME PG_USER PG_PASSWORD PG_HOST PG_PORT -commands = +commands = coverage run manage.py test --noinput {posargs:tenant_schemas} coverage report -m --include=../tenant_schemas/* From 6f6c871a0c4b797e655fe4bea29f802ca3b3e798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Raimbault?= Date: Wed, 12 Apr 2017 07:08:55 +0200 Subject: [PATCH 04/11] Fix documentation about custom management commands (#464) --- docs/test.rst | 7 ++++--- docs/use.rst | 13 ++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/test.rst b/docs/test.rst index 459b0c4..65968c6 100644 --- a/docs/test.rst +++ b/docs/test.rst @@ -1,6 +1,7 @@ -================== +===== Tests -================== +===== + Running the tests ----------------- Run these tests from the project ``dts_test_project``, it comes prepacked with the correct settings file and extra apps to enable tests to ensure different apps can exist in ``SHARED_APPS`` and ``TENANT_APPS``. @@ -27,7 +28,7 @@ Because django will not create tenants for you during your tests, we have packed class BaseSetup(TenantTestCase): def setUp(self): self.c = TenantClient(self.tenant) - + def test_user_profile_view(self): response = self.c.get(reverse('user_profile')) self.assertEqual(response.status_code, 200) diff --git a/docs/use.rst b/docs/use.rst index da4cf13..4373d09 100644 --- a/docs/use.rst +++ b/docs/use.rst @@ -1,6 +1,7 @@ =========================== Using django-tenant-schemas =========================== + Supported versions ------------------ You can use ``django-tenant-schemas`` with currently maintained versions of Django -- see the `Django's release process `_ and the present list of `Supported Versions `_. @@ -9,7 +10,7 @@ It is necessary to use a PostgreSQL database. ``django-tenant-schemas`` will ens Creating a Tenant ----------------- -Creating a tenant works just like any other model in django. The first thing we should do is to create the ``public`` tenant to make our main website available. We'll use the previous model we defined for ``Client``. +Creating a tenant works just like any other model in Django. The first thing we should do is to create the ``public`` tenant to make our main website available. We'll use the previous model we defined for ``Client``. .. code-block:: python @@ -43,7 +44,7 @@ Any call to the methods ``filter``, ``get``, ``save``, ``delete`` or any other f Management commands ------------------- -Every command except tenant_command runs by default on all tenants. You can also create your own commands that run on every tenant by inheriting ``BaseTenantCommand``. +By default, base commands run on the public tenant but you can also own commands that run on a specific tenant by inheriting ``BaseTenantCommand``. For example, if you have the following ``do_foo`` command in the ``foo`` app: @@ -57,7 +58,7 @@ For example, if you have the following ``do_foo`` command in the ``foo`` app: def handle(self, *args, **options): do_foo() -You could create a wrapper command ``tenant_do_foo`` by using ``BaseTenantCommand`` like so: +You could create a wrapper command by using ``BaseTenantCommand``: ``foo/management/commands/tenant_do_foo.py`` @@ -68,11 +69,13 @@ You could create a wrapper command ``tenant_do_foo`` by using ``BaseTenantComman class Command(BaseTenantCommand): COMMAND_NAME = 'do_foo' -To run only a particular schema, there is an optional argument called ``--schema``. +To run the command on a particular schema, there is an optional argument called ``--schema``. .. code-block:: bash - ./manage.py migrate_schemas --schema=customer1 + ./manage.py tenant_command do_foo --schema=customer1 + +If you omit the ``schema`` argument, the interactive shell will ask you to select one. migrate_schemas ~~~~~~~~~~~~~~~ From 6b8d41469ac8d376291101caddff9e161a0da693 Mon Sep 17 00:00:00 2001 From: Gary Reynolds Date: Sun, 16 Apr 2017 22:35:33 +1000 Subject: [PATCH 05/11] Updates for Django 1.11 --- docs/conf.py | 4 ++-- docs/use.rst | 4 ++-- tox.ini | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 3b032f3..971871a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -94,8 +94,8 @@ pygments_style = 'sphinx' intersphinx_mapping = { 'django': ( - 'https://docs.djangoproject.com/en/1.10/', - 'https://docs.djangoproject.com/en/1.10/_objects/'), + 'https://docs.djangoproject.com/en/1.11/', + 'https://docs.djangoproject.com/en/1.11/_objects/'), } # -- Options for HTML output --------------------------------------------------- diff --git a/docs/use.rst b/docs/use.rst index 4373d09..4085fba 100644 --- a/docs/use.rst +++ b/docs/use.rst @@ -4,9 +4,9 @@ Using django-tenant-schemas Supported versions ------------------ -You can use ``django-tenant-schemas`` with currently maintained versions of Django -- see the `Django's release process `_ and the present list of `Supported Versions `_. +You can use ``django-tenant-schemas`` with currently maintained versions of Django -- see the `Django's release process `_ and the present list of `Supported Versions `_. -It is necessary to use a PostgreSQL database. ``django-tenant-schemas`` will ensure compatibility with the minimum required version of the latest Django release. At this time that is PostgreSQL 9.2, the minimum for Django 1.10. +It is necessary to use a PostgreSQL database. ``django-tenant-schemas`` will ensure compatibility with the minimum required version of the latest Django release. At this time that is PostgreSQL 9.3, the minimum for Django 1.11. Creating a Tenant ----------------- diff --git a/tox.ini b/tox.ini index 6071ab3..ffea785 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py{27,35}-dj{18,19,110,111} +envlist = py{27,35}-dj{18,110,111} [testenv] usedevelop = True From 090f5b3ef7bb5680461d143327133cc2deb88fdd Mon Sep 17 00:00:00 2001 From: Gary Reynolds Date: Sun, 16 Apr 2017 22:57:06 +1000 Subject: [PATCH 06/11] =?UTF-8?q?Bump=20version:=201.7.0=20=E2=86=92=201.8?= =?UTF-8?q?.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 72e6b8f..fb542ed 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.7.0 +current_version = 1.8.0 commit = True tag = True From 8634634b1c34215f99d05eaf0921f19d0bb6fbf0 Mon Sep 17 00:00:00 2001 From: Adnan Umer Date: Mon, 17 Apr 2017 15:52:37 +0500 Subject: [PATCH 07/11] Django 1.9 Support --- tenant_schemas/template_loaders.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tenant_schemas/template_loaders.py b/tenant_schemas/template_loaders.py index 24c36da..4889edf 100644 --- a/tenant_schemas/template_loaders.py +++ b/tenant_schemas/template_loaders.py @@ -4,28 +4,28 @@ multi-tenant setting """ import hashlib + from django import VERSION as DJANGO_VERSION from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.db import connection +from django.template import TemplateDoesNotExist from django.template.base import Template from django.template.loaders.base import Loader as BaseLoader from django.utils._os import safe_join from django.utils.encoding import force_bytes + from tenant_schemas.postgresql_backend.base import FakeTenant -DJANGO_1_10 = DJANGO_VERSION[0] == 1 and DJANGO_VERSION[1] >= 10 +DJANGO_1_9 = DJANGO_VERSION[0] == 1 and DJANGO_VERSION[1] >= 9 -if DJANGO_1_10: - from django.template import Origin, TemplateDoesNotExist +if DJANGO_1_9: + from django.template import Origin def make_origin(engine, name, loader, template_name, dirs): return Origin(name=name, template_name=template_name, loader=loader) else: - from django.template.base import TemplateDoesNotExist - - def make_origin(engine, name, loader, template_name, dirs): return engine.make_origin(name, loader, template_name, dirs) From a21ed181fee5b999a2b03ce028440bf568d47fb8 Mon Sep 17 00:00:00 2001 From: Adnan Umer Date: Mon, 17 Apr 2017 15:53:56 +0500 Subject: [PATCH 08/11] Unit Tests for CachedLoader --- tenant_schemas/tests/__init__.py | 5 +-- .../tests/template_loader/__init__.py | 1 + .../template_loader/templates/hello.html | 1 + .../test_cached_template_loader.py | 31 +++++++++++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tenant_schemas/tests/template_loader/__init__.py create mode 100755 tenant_schemas/tests/template_loader/templates/hello.html create mode 100755 tenant_schemas/tests/template_loader/test_cached_template_loader.py diff --git a/tenant_schemas/tests/__init__.py b/tenant_schemas/tests/__init__.py index 09a3f81..2b6c0f2 100644 --- a/tenant_schemas/tests/__init__.py +++ b/tenant_schemas/tests/__init__.py @@ -1,5 +1,6 @@ -from .test_routes import * -from .test_tenants import * +from .template_loader import * from .test_cache import * from .test_log import * +from .test_routes import * +from .test_tenants import * from .test_utils import * diff --git a/tenant_schemas/tests/template_loader/__init__.py b/tenant_schemas/tests/template_loader/__init__.py new file mode 100644 index 0000000..ac17d9d --- /dev/null +++ b/tenant_schemas/tests/template_loader/__init__.py @@ -0,0 +1 @@ +from .test_cached_template_loader import CachedLoaderTests diff --git a/tenant_schemas/tests/template_loader/templates/hello.html b/tenant_schemas/tests/template_loader/templates/hello.html new file mode 100755 index 0000000..7f54a62 --- /dev/null +++ b/tenant_schemas/tests/template_loader/templates/hello.html @@ -0,0 +1 @@ +Hello! (Django templates) diff --git a/tenant_schemas/tests/template_loader/test_cached_template_loader.py b/tenant_schemas/tests/template_loader/test_cached_template_loader.py new file mode 100755 index 0000000..39facfe --- /dev/null +++ b/tenant_schemas/tests/template_loader/test_cached_template_loader.py @@ -0,0 +1,31 @@ +import os + +from django.template.loader import get_template +from django.test import SimpleTestCase, override_settings + + +@override_settings( + TEMPLATES=[ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(os.path.dirname(__file__), "templates") + ], + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.request', + ], + 'loaders': [ + ('tenant_schemas.template_loaders.CachedLoader', ( + 'tenant_schemas.template_loaders.FilesystemLoader', + 'django.template.loaders.filesystem.Loader' + )) + ] + }, + } + ] +) +class CachedLoaderTests(SimpleTestCase): + def test_get_template(self): + template = get_template("hello.html") + self.assertEqual(template.render(), "Hello! (Django templates)\n") From ab129048269511504ebe5491810ba5bae6d4601c Mon Sep 17 00:00:00 2001 From: Adnan Umer Date: Mon, 17 Apr 2017 15:54:16 +0500 Subject: [PATCH 09/11] Migrated to TEMPLATES settings --- dts_test_project/dts_test_project/settings.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dts_test_project/dts_test_project/settings.py b/dts_test_project/dts_test_project/settings.py index 245b017..9378c67 100644 --- a/dts_test_project/dts_test_project/settings.py +++ b/dts_test_project/dts_test_project/settings.py @@ -10,8 +10,8 @@ https://docs.djangoproject.com/en/1.8/ref/settings/ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os -BASE_DIR = os.path.dirname(os.path.dirname(__file__)) +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ @@ -28,7 +28,6 @@ ALLOWED_HOSTS = [] DEFAULT_FILE_STORAGE = 'tenant_schemas.storage.TenantFileSystemStorage' - # Application definition SHARED_APPS = ( @@ -74,7 +73,6 @@ ROOT_URLCONF = 'dts_test_project.urls' WSGI_APPLICATION = 'dts_test_project.wsgi.application' - # Database # https://docs.djangoproject.com/en/1.8/ref/settings/#databases @@ -111,6 +109,16 @@ TEMPLATE_CONTEXT_PROCESSORS = ( 'django.contrib.messages.context_processors.messages', ) +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'OPTIONS': { + 'context_processors': TEMPLATE_CONTEXT_PROCESSORS + }, + } +] + # Internationalization # https://docs.djangoproject.com/en/1.8/topics/i18n/ @@ -124,7 +132,6 @@ USE_L10N = True USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.8/howto/static-files/ From c4e34cdfdadfb0b7dd6896b9c23703062d8ac101 Mon Sep 17 00:00:00 2001 From: Gary Reynolds Date: Fri, 2 Jun 2017 06:56:57 +1000 Subject: [PATCH 10/11] Remove Django 1.9 from testing matrix, unsupported version. --- .travis.yml | 1 - tox.ini | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 845cc71..d83cf90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,6 @@ addons: install: pip install -q tox-travis env: - DJANGO=1.8 - - DJANGO=1.9 - DJANGO=1.10 - DJANGO=1.11 matrix: diff --git a/tox.ini b/tox.ini index 839fe27..29ee264 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,9 @@ [tox] -envlist = py{27,35}-dj{18,19,110,111}-{standard,parallel} +envlist = py{27,35}-dj{18,110,111}-{standard,parallel} [travis:env] DJANGO = 1.8: dj18-{standard,parallel} - 1.9: dj19-{standard,parallel} 1.10: dj110-{standard,parallel} 1.11: dj111-{standard,parallel} @@ -16,9 +15,8 @@ deps = mock tblib dj18: Django~=1.8.0 - dj19: Django~=1.9.0 dj110: Django~=1.10.0 - dj111: Django~=1.11rc1 + dj111: Django~=1.11.0 changedir = dts_test_project From bd99102e2e185d319bc7d5d12a208f3cf947a23f Mon Sep 17 00:00:00 2001 From: Gary Reynolds Date: Fri, 2 Jun 2017 17:56:37 +1000 Subject: [PATCH 11/11] Deal with backwards compatibility by exception. --- tenant_schemas/template_loaders.py | 9 +++------ tenant_schemas/test/cases.py | 4 ---- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/tenant_schemas/template_loaders.py b/tenant_schemas/template_loaders.py index 4889edf..6224a26 100644 --- a/tenant_schemas/template_loaders.py +++ b/tenant_schemas/template_loaders.py @@ -5,7 +5,6 @@ multi-tenant setting import hashlib -from django import VERSION as DJANGO_VERSION from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.db import connection @@ -17,15 +16,13 @@ from django.utils.encoding import force_bytes from tenant_schemas.postgresql_backend.base import FakeTenant -DJANGO_1_9 = DJANGO_VERSION[0] == 1 and DJANGO_VERSION[1] >= 9 - -if DJANGO_1_9: +try: from django.template import Origin - def make_origin(engine, name, loader, template_name, dirs): return Origin(name=name, template_name=template_name, loader=loader) -else: + +except ImportError: # Django 1.8 backwards compatibility def make_origin(engine, name, loader, template_name, dirs): return engine.make_origin(name, loader, template_name, dirs) diff --git a/tenant_schemas/test/cases.py b/tenant_schemas/test/cases.py index 4fe8b36..beef8dd 100644 --- a/tenant_schemas/test/cases.py +++ b/tenant_schemas/test/cases.py @@ -1,15 +1,11 @@ from django.conf import settings from django.core.management import call_command -from django.conf import settings from django.db import connection from django.test import TestCase - from tenant_schemas.utils import get_public_schema_name, get_tenant_model ALLOWED_TEST_DOMAIN = '.test.com' -ALLOWED_TEST_DOMAIN = '.test.com' - class TenantTestCase(TestCase): @classmethod