Repository: GeotrekCE/Geotrek-admin

Issue:
Utiliser un schema Postgres dédié pour l'application
- codes des triggers à revoir
- compatibilité django  http://beatpanic.info/postgresql-schema-support-postgis-and-django.html



Discussion:

Resolving patch:
diff --git a/geotrek/common/__init__.py b/geotrek/common/__init__.py
--- a/geotrek/common/__init__.py
+++ b/geotrek/common/__init__.py
@@ -13,7 +13,7 @@
 
 from mapentity.helpers import api_bbox
 
-from geotrek.common.utils.postgresql import load_sql_files
+from geotrek.common.utils.postgresql import load_sql_files, move_models_to_schemas
 
 
 """
@@ -25,6 +25,7 @@
 def run_initial_sql_post_migrate(sender, **kwargs):
     app_label = kwargs.get('app')
     load_sql_files(app_label)
+    move_models_to_schemas(app_label)
 
 
 def run_initial_sql_post_syncdb(sender, **kwargs):
@@ -32,6 +33,7 @@ def run_initial_sql_post_syncdb(sender, **kwargs):
     models_module = app.__name__
     app_label = models_module.rsplit('.')[-2]
     load_sql_files(app_label)
+    move_models_to_schemas(app_label)
 
 
 def check_srid_has_meter_unit(sender, **kwargs):
diff --git a/geotrek/common/utils/postgresql.py b/geotrek/common/utils/postgresql.py
--- a/geotrek/common/utils/postgresql.py
+++ b/geotrek/common/utils/postgresql.py
@@ -6,6 +6,7 @@
 
 from django.db import connection, models
 from django.conf import settings
+from django.db.models import get_app, get_models
 
 
 logger = logging.getLogger(__name__)
@@ -96,3 +97,45 @@ def load_sql_files(app_label):
                             (sql_file, e))
             traceback.print_exc()
             raise
+
+
+def move_models_to_schemas(app_label):
+    """
+    Move models tables to PostgreSQL schemas.
+
+    Views, functions and triggers will be moved in Geotrek app SQL files.
+    """
+    app = get_app(app_label)
+    default_schema = settings.DATABASE_SCHEMAS.get('default')
+    app_schema = settings.DATABASE_SCHEMAS.get(app_label, default_schema)
+
+    table_schemas = {}
+    for model in get_models(app):
+        model_name = model._meta.module_name
+        table_name = model._meta.db_table
+        model_schema = settings.DATABASE_SCHEMAS.get(model_name, app_schema)
+        table_schemas.setdefault(model_schema, []).append(table_name)
+
+        for m2m_field in model._meta.many_to_many:
+            table_name = m2m_field.db_table
+            if table_name:
+                table_schemas[model_schema].append(table_name)
+
+    cursor = connection.cursor()
+
+    for schema_name in table_schemas.keys():
+        try:
+            sql = "CREATE SCHEMA %s;" % model_schema
+            cursor.execute(sql)
+            logger.info("Created schema %s" % model_schema)
+        except Exception:
+            logger.debug("Schema %s already exists." % model_schema)
+
+    for schema_name, tables in table_schemas.items():
+        for table_name in tables:
+            try:
+                sql = "ALTER TABLE %s SET SCHEMA %s;" % (table_name, schema_name)
+                cursor.execute(sql)
+                logger.info("Moved %s to schema %s" % (table_name, schema_name))
+            except Exception:
+                logger.debug("Table %s already in schema %s" % (table_name, schema_name))
diff --git a/geotrek/settings/base.py b/geotrek/settings/base.py
--- a/geotrek/settings/base.py
+++ b/geotrek/settings/base.py
@@ -23,6 +23,7 @@
 DATABASES = {
     'default': {
         'ENGINE': 'django.contrib.gis.db.backends.postgis',
+        'OPTIONS': {},
         'NAME': '',                      # Or path to database file if using sqlite3.
         'USER': '',                      # Not used with sqlite3.
         'PASSWORD': '',                  # Not used with sqlite3.
@@ -31,6 +32,36 @@
     }
 }
 
+#
+# PostgreSQL Schemas for apps and models.
+#
+# Caution: editing this setting might not be enough.
+# Indeed, it won't apply to apps that not managed of South, nor database views and functions.
+# See all sql/*-schemas.sql files in each Geotrek app.
+#
+DATABASE_SCHEMAS = {
+    'default': 'geotrek',
+
+    'auth': 'django',
+    'django': 'django',
+    'easy_thumbnails': 'django',
+    'south': 'django',
+    'feedback': 'gestion',
+    'infrastructure': 'gestion',
+    'maintenance': 'gestion',
+    'tourism': 'tourisme',
+    'trekking': 'rando',
+    'zoning': 'zonage',
+    'land': 'foncier',
+}
+
+DATABASES['default']['OPTIONS'] = {
+    'options': '-c search_path=public,%s' % ','.join(set(DATABASE_SCHEMAS.values()))
+}
+
+#
+# Authentication
+#
 AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)
 AUTH_PROFILE_MODULE = 'authent.UserProfile'
 


Test patch: