web-dev-qa-db-fra.com

Schémas Django et postgresql

J'ai essayé de résoudre celui-ci toute la semaine, aide très appréciée.

J'ai plusieurs schémas dans une base de données postgres et j'aimerais pouvoir les mapper depuis la même application ou entre différentes applications Django.

Certains des schémas sont:

des échantillons

les fouilles

géophysique

...

J'ai essayé la méthode recommandée, mais je ne reçois aucune donnée à afficher à partir des schémas, je ne peux me connecter qu'au schéma public avec des tables gérées. Voici les connexions à la base de données à partir du fichier settings.py.

DATABASES = {

'default': {
        'ENGINE': 'Django.db.backends.postgresql_psycopg2',
        'OPTIONS': {
            'options': '-c search_path=Django,public'
        },
        'NAME': 'gygaia',
        'USER': 'appuser',
        'PASSWORD': 'secret',
},

'samples': {
        'ENGINE': 'Django.db.backends.postgresql_psycopg2',
        'OPTIONS': {
            'options': '-c search_path=samples,public'
        },
        'NAME': 'gygaia',
        'USER': 'appuser',
        'PASSWORD': 'secret',
},
}

source: https://www.amvtek.com/blog/posts/2014/Jun/13/accessing-multiple-postgres-schemas-from-Django/

Dans le model.py j'ajoute:

    from Django.db import models

    # Create your models here.
    class Storage(models.Model):
        #id = models.IntegerField(default=0)
        storage_id = models.AutoField(primary_key=True)
        store_name = models.CharField(max_length=200, default='')
        address_1 = models.CharField(max_length=200, default='')
        address_2 = models.CharField(max_length=200, default='')
        region = models.CharField(max_length=200, default='')
        city = models.CharField(max_length=200, default='')
        Zip = models.CharField(max_length=200, default='')
        country = models.CharField(max_length=200, default="Turkey")
        user = models.CharField(max_length=200, default="Gygaia")
        datestamp = models.DateTimeField(auto_now=True)

    class Meta():
        managed=False
        db_table = 'samples\".\"store'

Je ne veux pas restreindre les schémas aux utilisateurs, et la base de données a été créée il y a quelques années. Je ne suis donc pas autorisée à la regrouper sous un seul schéma. Je sais qu'il existe diverses solutions publiées sur stackoverflow et sur d'autres sources d'Internet. J'ai déjà essayé ces solutions, mais je ne parviens pas à faire en sorte que cela fonctionne. Des idées comment résoudre cela?

5
Gary Nobles

Dans la mesure où Django ne prend pas en charge les schémas de base de données Postgres prêts à l'emploi, utilisez un routeur database

J'ai créé une base de données de test pour essayer ceci, voici comment la reproduire:

Créez une base de données de test avec psql:

CREATE USER tester WITH PASSWORD 'lol so easy';
CREATE DATABASE multi_schema_db WITH OWNER tester;
CREATE SCHEMA samples AUTHORIZATION tester;
CREATE TABLE samples.my_samples (
  id          INTEGER   NOT NULL PRIMARY KEY,
  description CHAR(255) NOT NULL
);

Ajoutez les schémas aux paramètres en tant que connexions à la base de données différentes. N'oubliez pas d'ajouter Host pour éviter l'erreur «L'authentification par l'homologue a échoué».

DATABASES = {

'default': {
    'ENGINE': 'Django.db.backends.postgresql_psycopg2',
    'OPTIONS': {
        'options': '-c search_path=Django,public'
    },
    'NAME': 'multi_schema_db',
    'USER': 'tester',
    'PASSWORD': 'lol so easy',
    'Host': 'localhost'

},

'samples': {
    'ENGINE': 'Django.db.backends.postgresql_psycopg2',
    'OPTIONS': {
        'options': '-c search_path=samples,public'
    },
    'NAME': 'multi_schema_db',
    'USER': 'tester',
    'PASSWORD': 'lol so easy',
    'Host': 'localhost'
},

}

Créez ensuite le modèle MySample:

from Django.db import models

class MySample(models.Model):
    description = models.CharField(max_length=255, null=False)

    class Meta:
        managed = False
        db_table = 'my_samples'

Créez un routeur de base de données pour diriger toutes les requêtes relatives aux exemples vers la base de données exemple:

from database_test.models import MySample

ROUTED_MODELS = [MySample]


class MyDBRouter(object):

    def db_for_read(self, model, **hints):
        if model in ROUTED_MODELS:
            return 'samples'
        return None

    def db_for_write(self, model, **hints):
        if model in ROUTED_MODELS:
            return 'samples'
        return None

Fondamentalement, le routeur acheminera tous les modèles spécifiés dans ROUTED_MODELS vers la connexion à la base de données samples et renverra Aucun pour tous les autres modèles. Cela les acheminera vers la connexion à la base de données default.

Enfin, ajoutez le routeur à votre settings.py

DATABASE_ROUTERS = ('database_test.db_router.MyDBRouter',)

Et maintenant, lorsque vous effectuez une requête pour le modèle MySample, il va extraire les données du schéma samples.

7
tarikki

J'ai aussi consulté cette source, mais je ne pouvais pas la résoudre comme vous, mais en effectuant des tests, j'ai obtenu les résultats suivants.

Si nous avons par exemple, les schémas foo et bar, écrivant dans le Meta:

class MySample1 (models.Model):
     description = models.CharField (max_length = 255, null = False)
     class Goal:
         managed = True
         db_table = 'fo\".\"my_samples1'

class MySample2 (models.Model):
     description = models.CharField (max_length = 255, null = False)
     class Goal:
         managed = True
         db_table = 'bar\".\"my_samples2'

Ensuite, nous pouvons rediriger chaque modèle vers le schéma souhaité, à condition que la variable soit gérée dans True. La limitation est que nous devons nommer la table nous-mêmes.