4

J'ai écrit un site Django qui utilise deux bases de données différentes. L'un est local, appelons-le, "Django", base de données qui stocke toutes les tables standard à partir d'une installation standard assez simple - auth, sites, commentaires, etc. - plus quelques tables supplémentaires."Clés étrangères" à travers des bases de données très distinctes dans Django

La plupart des données, y compris les utilisateurs, proviennent d'une base de données sur un autre serveur, appelons-la la base de données "Legacy".

Je suis à la recherche de suggestions sur les façons propres et pythoniques de la connexion des deux bases de données, en particulier en ce qui concerne les utilisateurs. J'utilise un modèle de proxy, qui fonctionne très bien quand je peux l'utiliser explicitement, mais je rencontre des problèmes lorsque j'accède à l'objet utilisateur en tant qu'objet associé (par exemple, lorsque j'utilise le django intégré système de commentaires).

Voici ce que le code ressemble à:

models.py: (points à la base de données Django)

from django.db import models 
from django.conf import settings 
from django.contrib.auth.models import User as AuthUser, UserManager as AuthUserManager, AnonymousUser as AuthAnonymousUser 

class UserPerson(models.Model): 
    user = models.OneToOneField(AuthUser, related_name="person") 
    person_id = models.PositiveIntegerField(verbose_name='Legacy ID') 

    def __unicode__(self): 
     return "%s" % self.get_person() 

    def get_person(self): 
     if not hasattr(self, '_person'): 
      from legacy_models import Person 
      from utils import get_person_model 
      Person = get_person_model() or Person 
      self._person = Person.objects.get(pk=self.person_id) 
     return self._person 
    person=property(get_person) 

class UserManager(AuthUserManager): 
    def get_for_id(self, id): 
     return self.get(person__person_id=id) 

    def get_for_email(self, email): 
     try: 
      person = Person.objects.get(email=email) 
      return self.get_for_id(person.pk) 
     except Person.DoesNotExist: 
      return User.DoesNotExist 

    def create_user(self, username, email, password=None, *args, **kwargs): 
     user = super(UserManager,self).create_user(username, email, password, *args, **kwargs) 
     try: 
      person_id = Person.objects.get(email=email).pk 
      userperson, created = UserPerson.objects.get_or_create(user=user, person_id=person_id) 
     except Person.DoesNotExist: 
      pass 
     return user 

class AnonymousUser(AuthAnonymousUser): 
    class Meta: 
     proxy = True 

class User(AuthUser): 
    class Meta: 
     proxy=True 

    def get_profile(self): 
     """ 
     Returns the Person record from the legacy database 
     """ 
     if not hasattr(self, '_profile_cache'): 
      self._profile_cache = UserPerson.objects.get(user=self).person 
     return self._profile_cache 

    objects = UserManager() 

legacy_models.py: (points à la base de données "Legacy")

class Person(models.Model): 
    id = models.AutoField(primary_key=True, db_column='PeopleID') # Field name made lowercase. 
    code = models.CharField(max_length=40, blank=True, db_column="person_code", unique=True) 
    first_name = models.CharField(max_length=50, db_column='firstName', blank=True) # Field name made lowercase. 
    last_name = models.CharField(max_length=50, db_column='lastName', blank=True) # Field name made lowercase. 
    email = models.CharField(max_length=255, blank=True) 

    def __unicode__(self): 
     return "%s %s" % (self.first_name, self.last_name) 

    def get_user(self): 
     from models import User 
     if not hasattr(self,'_user'): 
      self._user = User.objects.get_for_id(self.pk) 
     return self._user 
    user = property(get_user) 

    class Meta: 
     db_table = u'People' 

J'ai aussi fouetté mon propre middleware, donc request.user est le pr oxy User objet aussi.

Le vrai problème est quand j'utilise quelque chose qui a l'utilisateur comme un objet connexe, en particulier dans un modèle où j'ai encore moins de contrôle.

Dans le modèle:

{{ request.user.get_profile }} 
{# this works and returns the related Person object for the user #} 

{% for comment in comments %} {# retrieved using the built-in comments app %} 
    {{ comment.user.get_profile }} 
    {# this throws an error because AUTH_PROFILE_MODULE is not defined by design #} 
{% endfor %} 

Court de créer une version enveloppée du système de commentaires qui utilise mon proxy modèle de l'utilisateur à la place, est-il autre chose que je peux faire?

Répondre

3

Voici comment je l'ai résolu. J'ai arrêté complètement d'utiliser le proxy utilisateur.

models.py:

from django.db import models 
from legacy_models import Person 
from django.contrib.auth.models import User 

class UserPerson(models.Model): 
    user = models.OneToOneField(User, related_name="person") 
    person_id = models.PositiveIntegerField(verbose_name='PeopleID', help_text='ID in the Legacy Login system.') 

    def __unicode__(self): 
     return "%s" % self.get_person() 

    def get_person(self): 
     if not hasattr(self, '_person'): 
      self._person = Person.objects.get(pk=self.person_id) 
     return self._person 
    person=property(get_person) 

class LegacyPersonQuerySet(models.query.QuerySet): 
    def get(self, *args, **kwargs): 
     person_id = UserPerson.objects.get(*args, **kwargs).person_id 
     return LegacyPerson.objects.get(pk=person_id) 

class LegacyPersonManager(models.Manager): 
    def get_query_set(self, *args, **kwargs): 
     return LegacyPersonQuerySet(*args, **kwargs) 

class LegacyPerson(Person): 
    objects = LegacyPersonManager() 

    class Meta: 
     proxy=True 

et legacy_models.py:

class Person(models.Model): 
    id = models.AutoField(primary_key=True, db_column='PeopleID') # Field name made lowercase. 
    code = models.CharField(max_length=40, blank=True, db_column="person_code", unique=True) 
    first_name = models.CharField(max_length=50, db_column='firstName', blank=True) # Field name made lowercase. 
    last_name = models.CharField(max_length=50, db_column='lastName', blank=True) # Field name made lowercase. 
    email = models.CharField(max_length=255, blank=True) 

    def __unicode__(self): 
     return "%s %s" % (self.first_name, self.last_name) 

    def get_user(self): 
     from models import User 
     if not hasattr(self,'_user'): 
      self._user = User.objects.get_for_id(self.pk) 
     return self._user 
    def set_user(self, user=None): 
     self._user=user 
    user = property(get_user, set_user) 

    class Meta: 
     db_table = u'People' 

Enfin, settings.py:

AUTH_PROFILE_MODULE = 'myauth.LegacyPerson' 

C'est une solution plus simple, mais au moins cela fonctionne! Cela signifie que chaque fois que je veux l'enregistrement existant, je dois appeler user_profile, et cela signifie qu'il y a une requête supplémentaire pour chaque enregistrement d'utilisateur, mais c'est un compromis équitable car en fait, il est peu probable que je le fasse une vérification croisée que souvent.

Questions connexes