Domanda

Ho scrivere un sito Django che utilizza due database diversi. Uno è il locale, chiamiamolo, "Django", database che memorizza tutte le tabelle standard da uno standard abbastanza installazione - autenticazione, siti, commenti, ecc. - più alcuni tavoli extra

La maggior parte dei dati, compresi gli utenti, proviene da un database su un altro server, chiamiamolo il database "Legacy".

sto cercando suggerimenti su pulito, modi divinatorio per collegare le due basi di dati, in particolare per quanto riguarda gli utenti.

Io sto usando un modello di delega, che funziona alla grande quando posso esplicitamente usarlo, ma io incorrere in problemi quando sto accedere all'oggetto utente come un oggetto correlato (ad esempio, quando si utilizza il built-in Django commenti sistema).

Ecco cosa gli sguardi codice come:

models.py : (punta al database di 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 : (punta al database di "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'

Ho anche montata una mia middleware, in modo request.user è l'oggetto User delega anche.

Il vero problema è quando sto usando qualcosa che ha utente come un oggetto correlato, in particolare in un modello in cui ho ancora meno controllo.

Nel modello:

{{ 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 %}

A corto di creare una versione avvolto del sistema di commenti, che usa il mio delega modello User, invece, c'è qualcos'altro che posso fare?

È stato utile?

Soluzione

Ecco come ho risolto esso. Ho smesso di usare il proxy per l'utente del tutto.

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

e 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'

Infine, in settings.py :

AUTH_PROFILE_MODULE = 'myauth.LegacyPerson'

Si tratta di una soluzione più semplice, ma almeno funziona! Significa che ogni volta che voglio il record legacy devo chiamare user_profile, e significa che c'è una query aggiuntiva per ogni record utente, ma questa è una fiera-off, perché in realtà non è molto probabile che farò un controllo incrociato che spesso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top