“外键"跨 Django 中非常独立的数据库 [英] "Foreign Keys" across very separate databases in Django
问题描述
我正在编写一个使用两个不同数据库的 Django 站点.一个是本地数据库,我们称之为Django",该数据库存储来自非常标准的安装的所有标准表——身份验证、站点、评论等——以及一些额外的表.
I've writing a Django site that uses two different databases. One is the local, let's call it, "Django", database that stores all of the standard tables from a pretty standard install -- auth, sites, comments, etc. -- plus a few extra tables.
包括用户在内的大部分数据都来自另一台服务器上的数据库,我们称之为传统"数据库.
Most of the data, including users, comes from a database on another server, let's call it the "Legacy" database.
我正在寻找有关连接两个数据库的干净、pythonic 方式的建议,特别是关于用户的建议.
I'm looking for suggestions on clean, pythonic ways of connecting the two databases, particularly in regards to users.
我正在使用代理模型,当我可以显式使用它时效果很好,但是当我将用户对象作为相关对象访问时遇到了问题(例如,当使用内置的 django 注释时)系统).
I'm using a proxy model, which works great when I can explicitly use it, but I run into problems when I'm accessing the user object as a related object (for example, when using the built-in django comments system).
代码如下:
models.py:(指向Django数据库)
models.py: (points to the Django database)
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:(指向Legacy"数据库)
legacy_models.py: (points to the "Legacy" database)
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'
我也创建了自己的中间件,所以 request.user
也是代理 User
对象.
I've also whipped up my own middleware, so request.user
is the proxy User
object also.
真正的问题是当我使用将用户作为相关对象的东西时,尤其是在我控制更少的模板中.
The real problem is when I'm using something that has user as a related object, particularly in a template where I have even less control.
在模板中:
{{ 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 %}
除了创建使用我的代理用户模型的评论系统的包装版本之外,还有什么我可以做的吗?
Short of creating a wrapped version of the comments system which uses my proxy User model instead, is there anything else I can do?
推荐答案
这是我的解决方法.我完全停止使用用户代理.
Here's how I resolved it. I stopped using the User proxy altogether.
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
和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'
最后,在 settings.py 中:
AUTH_PROFILE_MODULE = 'myauth.LegacyPerson'
这是一个更简单的解决方案,但至少它有效!这确实意味着每当我想要遗留记录时,我都必须调用 user_profile
,这意味着每个用户记录都有一个额外的查询,但这是一个公平的权衡,因为实际上它不是我很可能会经常进行交叉检查.
This is a simpler solution, but at least it works! It does mean that whenever I want the legacy record I have to call user_profile
, and it means that there's an additional query for each user record, but this is a fair trade-off because actually it isn't very likely that I will be doing a cross check that often.
这篇关于“外键"跨 Django 中非常独立的数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!