2010-10-28 17 views
4

Avec Django multidb, il est assez facile d'écrire un router qui exécute une infrastructure maître/esclave. Mais est-il possible d'écrire un routeur qui écrit dans plusieurs bases de données? Mon cas d'utilisation est une collection de projets, tous exécutés sur le même domaine. Pour éviter que les utilisateurs ne s'inscrivent/se connectent sur tous les sites, je souhaite synchroniser les tables contrib.auth et contrib.sessions. Est-ce possible avec Django multidb ou devrais-je regarder dans les fonctionnalités de réplication du système de base de données (MySQL dans mon cas)?Django multidb: écrire dans plusieurs bases de données

Répondre

4

Je travaille actuellement sur un schéma de partitionnement Django. J'ai regardé le routeur Django mais j'ai décidé de lancer le mien.

quelques réflexions sur votre question:

  1. Une idée est d'utiliser une base de données, puis copier les données appropriées par l'utilisation de signaux Django sur post-enregistrement.

quelque chose like--

import settings.databases as dbs_list 

def post_save_function(UserModel): 
    for db in dbs_list: 
      UserModel.save(using=db,force_insert=True) 

sauver des objets utilisateur (au moins sur un modèle unique DB) semble enregistrer session, auth, données, etc. sous le capot par les différents magiques survenant à l'intérieur django .contrib, il est donc possible que vous n'ayez pas à entrer et à trouver les noms et les types de toutes ces tables de base de données. Pour soutenir la possibilité de ce travail, je jure avoir lu quelque part récemment (probablement sur l'un des articles du blog d'Alex Gaynor) que si un objet a une clé étrangère, Django essayera d'utiliser le même DB sur lequel l'objet vit (pour des raisons évidentes à la lumière de la façon dont Django opère généralement).

  1. une autre idée:

de l'exemple sur la page Django Multidb vous référencé Je me demande si quelque chose comme ce qui suit fonctionnerait:

leur code exemple:

def allow_syncdb(self, db, model): 
     "Explicitly put all models on all databases." 
     return True 

une modification possible:

def allow_syncdb (auto, db, modèle):

if isinstance(model,User): 
     return True 

    elif isinstance(model,Session): 
     return True 

    else: 
     ''' something appropriate -- 
      whatever your sharding schema is for other objects ''' 

regardant encore, ce code serait probablement plus utile que la fonction "db_for_write". mais vous avez l'idée.

il n'y a aucun doute que d'autres types de modèles que vous auriez à ajouter pour faire ce travail (toutes les choses auth, ce qui est vaste).

bonne chance! J'espère que cela sera utile d'une manière ou d'une autre.

Je suis intéressé par vos résultats et commentaires!

jb

+0

Bonjour, merci pour votre commentaire. Je n'ai plus cherché à résoudre ce problème particulier, puisque nous nous sommes installés sur un système LDAP/Kerberos pour fournir une authentification centralisée et une authentification unique. –

5

je pense que vous serez mieux mettre en œuvre un SSO ou un service OAuth

mais si vous voulez vous synchroniser vos utilisateurs de table entre deux bases de données et si vous utilisez votre propre userModel vous pouvez faire quelque chose comme ça

class MyUser(models.Model): 
    name = models.CharField(max_length=100) 
    user = models.ForeignKey(User, unique=True) 


    def save(self, ...): # ALL the signature 
     super(MyUser, self).save(using='database_1') 
     super(MyUser, self).save(using='database_2') 

vous pouvez aussi mettre un décorateur comme ça, comme ça, vous pouvez également l'utiliser pour synchroniser d'autres tables:

def save_multi_db(model_class): 

    def save_wrapper(save_func): 
     def new_save(self, *args, **kws): 
      super(model_class, self).save(using='database_1') 
      super(model_class, self).save(using='database_1') 
     return new_save 

    func = getattr(model_class, 'save') 
    setattr(model_class, 'save', save_wrapper(func)) 

    return save_wrapper 

# and use it like this: 

@save_multi_db 
class MyUser(models.Model): 
     .... 

Hope this aidera :) :)

+0

je dois changer le code source de Django pour que cela fonctionne (comme je l'ai dit dans la question, les tableaux que je veux répliquer sont de 'contrib.auth' et 'contrib.sessions'). Si possible, j'aimerais éviter de jouer avec Django lui-même. –

1

D'abord, je pense que ce que vous avez besoin est plus un cadre d'authentification unique, comme in this post

J'ai essayé la réponse de Mouad, mais je ne pouvais pas décorateur de la classe ouvrière ... Et il me semble cette solution ne permet pas d'avoir save() personnalisé dans les modèles.

Plus approprié à mon besoin, j'ai défini une classe générique personnalisée et remplace simplement la fonction save().

class MultiDbModel(models.Model): 
    class Meta: 
     abstract = True 

    def save(self, *args, **kwarg 
     for dbname in settings.DATABASES: 
      super(MultiDbModel, self).save(using=dbname) 

Et puis:

class MyObject(MultiDbModel): 
    [...] 
    def save(self, *args, **kwargs): 
     [custom save] 
     super(MyObject, self).save(args, kwargs)